{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# \u7b2c\u5341\u4e8c\u7ae0\uff1a\u5e76\u53d1\u7f16\u7a0b\n \u5bf9\u4e8e\u5e76\u53d1\u7f16\u7a0b, Python\u6709\u591a\u79cd\u957f\u671f\u652f\u6301\u7684\u65b9\u6cd5, \u5305\u62ec\u591a\u7ebf\u7a0b, \u8c03\u7528\u5b50\u8fdb\u7a0b, \u4ee5\u53ca\u5404\u79cd\u5404\u6837\u7684\u5173\u4e8e\u751f\u6210\u5668\u51fd\u6570\u7684\u6280\u5de7.\n\u8fd9\u4e00\u7ae0\u5c06\u4f1a\u7ed9\u51fa\u5e76\u53d1\u7f16\u7a0b\u5404\u79cd\u65b9\u9762\u7684\u6280\u5de7, \u5305\u62ec\u901a\u7528\u7684\u591a\u7ebf\u7a0b\u6280\u672f\u4ee5\u53ca\u5e76\u884c\u8ba1\u7b97\u7684\u5b9e\u73b0\u65b9\u6cd5."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 12.1 \u542f\u52a8\u4e0e\u505c\u6b62\u7ebf\u7a0b\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u95ee\u9898\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4f60\u8981\u4e3a\u9700\u8981\u5e76\u53d1\u6267\u884c\u7684\u4ee3\u7801\u521b\u5efa/\u9500\u6bc1\u7ebf\u7a0b"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u89e3\u51b3\u65b9\u6848\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "threading \u5e93\u53ef\u4ee5\u5728\u5355\u72ec\u7684\u7ebf\u7a0b\u4e2d\u6267\u884c\u4efb\u4f55\u7684\u5728 Python \u4e2d\u53ef\u4ee5\u8c03\u7528\u7684\u5bf9\u8c61\u3002\u4f60\u53ef\u4ee5\u521b\u5efa\u4e00\u4e2a Thread \u5bf9\u8c61\u5e76\u5c06\u4f60\u8981\u6267\u884c\u7684\u5bf9\u8c61\u4ee5 target \u53c2\u6570\u7684\u5f62\u5f0f\u63d0\u4f9b\u7ed9\u8be5\u5bf9\u8c61\u3002\n\u4e0b\u9762\u662f\u4e00\u4e2a\u7b80\u5355\u7684\u4f8b\u5b50\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# Code to execute in an independent thread\nimport time\ndef countdown(n):\n    while n > 0:\n        print('T-minus', n)\n        n -= 1\n        time.sleep(5)\n\n# Create and launch a thread\nfrom threading import Thread\nt = Thread(target=countdown, args=(10,))\nt.start()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5f53\u4f60\u521b\u5efa\u597d\u4e00\u4e2a\u7ebf\u7a0b\u5bf9\u8c61\u540e\uff0c\u8be5\u5bf9\u8c61\u5e76\u4e0d\u4f1a\u7acb\u5373\u6267\u884c\uff0c\u9664\u975e\u4f60\u8c03\u7528\u5b83\u7684 start() \u65b9\u6cd5\uff08\u5f53\u4f60\u8c03\u7528 start() \u65b9\u6cd5\u65f6\uff0c\u5b83\u4f1a\u8c03\u7528\u4f60\u4f20\u9012\u8fdb\u6765\u7684\u51fd\u6570\uff0c\u5e76\u628a\u4f60\u4f20\u9012\u8fdb\u6765\u7684\u53c2\u6570\u4f20\u9012\u7ed9\u8be5\u51fd\u6570\uff09\u3002Python\u4e2d\u7684\u7ebf\u7a0b\u4f1a\u5728\u4e00\u4e2a\u5355\u72ec\u7684\u7cfb\u7edf\u7ea7\u7ebf\u7a0b\u4e2d\u6267\u884c\uff08\u6bd4\u5982\u8bf4\u4e00\u4e2a POSIX \u7ebf\u7a0b\u6216\u8005\u4e00\u4e2a Windows \u7ebf\u7a0b\uff09\uff0c\u8fd9\u4e9b\u7ebf\u7a0b\u5c06\u7531\u64cd\u4f5c\u7cfb\u7edf\u6765\u5168\u6743\u7ba1\u7406\u3002\u7ebf\u7a0b\u4e00\u65e6\u542f\u52a8\uff0c\u5c06\u72ec\u7acb\u6267\u884c\u76f4\u5230\u76ee\u6807\u51fd\u6570\u8fd4\u56de\u3002\u4f60\u53ef\u4ee5\u67e5\u8be2\u4e00\u4e2a\u7ebf\u7a0b\u5bf9\u8c61\u7684\u72b6\u6001\uff0c\u770b\u5b83\u662f\u5426\u8fd8\u5728\u6267\u884c\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "if t.is_alive():\n    print('Still running')\nelse:\n    print('Completed')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4f60\u4e5f\u53ef\u4ee5\u5c06\u4e00\u4e2a\u7ebf\u7a0b\u52a0\u5165\u5230\u5f53\u524d\u7ebf\u7a0b\uff0c\u5e76\u7b49\u5f85\u5b83\u7ec8\u6b62\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "t.join()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Python\u89e3\u91ca\u5668\u76f4\u5230\u6240\u6709\u7ebf\u7a0b\u90fd\u7ec8\u6b62\u524d\u4ecd\u4fdd\u6301\u8fd0\u884c\u3002\u5bf9\u4e8e\u9700\u8981\u957f\u65f6\u95f4\u8fd0\u884c\u7684\u7ebf\u7a0b\u6216\u8005\u9700\u8981\u4e00\u76f4\u8fd0\u884c\u7684\u540e\u53f0\u4efb\u52a1\uff0c\u4f60\u5e94\u5f53\u8003\u8651\u4f7f\u7528\u540e\u53f0\u7ebf\u7a0b\u3002\n\u4f8b\u5982\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "t = Thread(target=countdown, args=(10,), daemon=True)\nt.start()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u540e\u53f0\u7ebf\u7a0b\u65e0\u6cd5\u7b49\u5f85\uff0c\u4e0d\u8fc7\uff0c\u8fd9\u4e9b\u7ebf\u7a0b\u4f1a\u5728\u4e3b\u7ebf\u7a0b\u7ec8\u6b62\u65f6\u81ea\u52a8\u9500\u6bc1\u3002\n\u9664\u4e86\u5982\u4e0a\u6240\u793a\u7684\u4e24\u4e2a\u64cd\u4f5c\uff0c\u5e76\u6ca1\u6709\u592a\u591a\u53ef\u4ee5\u5bf9\u7ebf\u7a0b\u505a\u7684\u4e8b\u60c5\u3002\u4f60\u65e0\u6cd5\u7ed3\u675f\u4e00\u4e2a\u7ebf\u7a0b\uff0c\u65e0\u6cd5\u7ed9\u5b83\u53d1\u9001\u4fe1\u53f7\uff0c\u65e0\u6cd5\u8c03\u6574\u5b83\u7684\u8c03\u5ea6\uff0c\u4e5f\u65e0\u6cd5\u6267\u884c\u5176\u4ed6\u9ad8\u7ea7\u64cd\u4f5c\u3002\u5982\u679c\u9700\u8981\u8fd9\u4e9b\u7279\u6027\uff0c\u4f60\u9700\u8981\u81ea\u5df1\u6dfb\u52a0\u3002\u6bd4\u5982\u8bf4\uff0c\u5982\u679c\u4f60\u9700\u8981\u7ec8\u6b62\u7ebf\u7a0b\uff0c\u90a3\u4e48\u8fd9\u4e2a\u7ebf\u7a0b\u5fc5\u987b\u901a\u8fc7\u7f16\u7a0b\u5728\u67d0\u4e2a\u7279\u5b9a\u70b9\u8f6e\u8be2\u6765\u9000\u51fa\u3002\u4f60\u53ef\u4ee5\u50cf\u4e0b\u8fb9\u8fd9\u6837\u628a\u7ebf\u7a0b\u653e\u5165\u4e00\u4e2a\u7c7b\u4e2d\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "class CountdownTask:\n    def __init__(self):\n        self._running = True\n\n    def terminate(self):\n        self._running = False\n\n    def run(self, n):\n        while self._running and n > 0:\n            print('T-minus', n)\n            n -= 1\n            time.sleep(5)\n\nc = CountdownTask()\nt = Thread(target=c.run, args=(10,))\nt.start()\nc.terminate() # Signal termination\nt.join()      # Wait for actual termination (if needed)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5982\u679c\u7ebf\u7a0b\u6267\u884c\u4e00\u4e9b\u50cfI/O\u8fd9\u6837\u7684\u963b\u585e\u64cd\u4f5c\uff0c\u90a3\u4e48\u901a\u8fc7\u8f6e\u8be2\u6765\u7ec8\u6b62\u7ebf\u7a0b\u5c06\u4f7f\u5f97\u7ebf\u7a0b\u4e4b\u95f4\u7684\u534f\u8c03\u53d8\u5f97\u975e\u5e38\u68d8\u624b\u3002\u6bd4\u5982\uff0c\u5982\u679c\u4e00\u4e2a\u7ebf\u7a0b\u4e00\u76f4\u963b\u585e\u5728\u4e00\u4e2aI/O\u64cd\u4f5c\u4e0a\uff0c\u5b83\u5c31\u6c38\u8fdc\u65e0\u6cd5\u8fd4\u56de\uff0c\u4e5f\u5c31\u65e0\u6cd5\u68c0\u67e5\u81ea\u5df1\u662f\u5426\u5df2\u7ecf\u88ab\u7ed3\u675f\u4e86\u3002\u8981\u6b63\u786e\u5904\u7406\u8fd9\u4e9b\u95ee\u9898\uff0c\u4f60\u9700\u8981\u5229\u7528\u8d85\u65f6\u5faa\u73af\u6765\u5c0f\u5fc3\u64cd\u4f5c\u7ebf\u7a0b\u3002\n\u4f8b\u5b50\u5982\u4e0b\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "class IOTask:\n    def terminate(self):\n        self._running = False\n\n    def run(self, sock):\n        # sock is a socket\n        sock.settimeout(5)        # Set timeout period\n        while self._running:\n            # Perform a blocking I/O operation w/ timeout\n            try:\n                data = sock.recv(8192)\n                break\n            except socket.timeout:\n                continue\n            # Continued processing\n            ...\n        # Terminated\n        return"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u8ba8\u8bba\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u7531\u4e8e\u5168\u5c40\u89e3\u91ca\u9501\uff08GIL\uff09\u7684\u539f\u56e0\uff0cPython \u7684\u7ebf\u7a0b\u88ab\u9650\u5236\u5230\u540c\u4e00\u65f6\u523b\u53ea\u5141\u8bb8\u4e00\u4e2a\u7ebf\u7a0b\u6267\u884c\u8fd9\u6837\u4e00\u4e2a\u6267\u884c\u6a21\u578b\u3002\u6240\u4ee5\uff0cPython \u7684\u7ebf\u7a0b\u66f4\u9002\u7528\u4e8e\u5904\u7406I/O\u548c\u5176\u4ed6\u9700\u8981\u5e76\u53d1\u6267\u884c\u7684\u963b\u585e\u64cd\u4f5c\uff08\u6bd4\u5982\u7b49\u5f85I/O\u3001\u7b49\u5f85\u4ece\u6570\u636e\u5e93\u83b7\u53d6\u6570\u636e\u7b49\u7b49\uff09\uff0c\u800c\u4e0d\u662f\u9700\u8981\u591a\u5904\u7406\u5668\u5e76\u884c\u7684\u8ba1\u7b97\u5bc6\u96c6\u578b\u4efb\u52a1\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u6709\u65f6\u4f60\u4f1a\u770b\u5230\u4e0b\u8fb9\u8fd9\u79cd\u901a\u8fc7\u7ee7\u627f Thread \u7c7b\u6765\u5b9e\u73b0\u7684\u7ebf\u7a0b\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from threading import Thread\n\nclass CountdownThread(Thread):\n    def __init__(self, n):\n        super().__init__()\n        self.n = n\n    def run(self):\n        while self.n > 0:\n\n            print('T-minus', self.n)\n            self.n -= 1\n            time.sleep(5)\n\nc = CountdownThread(5)\nc.start()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5c3d\u7ba1\u8fd9\u6837\u4e5f\u53ef\u4ee5\u5de5\u4f5c\uff0c\u4f46\u8fd9\u4f7f\u5f97\u4f60\u7684\u4ee3\u7801\u4f9d\u8d56\u4e8e threading \u5e93\uff0c\u6240\u4ee5\u4f60\u7684\u8fd9\u4e9b\u4ee3\u7801\u53ea\u80fd\u5728\u7ebf\u7a0b\u4e0a\u4e0b\u6587\u4e2d\u4f7f\u7528\u3002\u4e0a\u6587\u6240\u5199\u7684\u90a3\u4e9b\u4ee3\u7801\u3001\u51fd\u6570\u90fd\u662f\u4e0e threading \u5e93\u65e0\u5173\u7684\uff0c\u8fd9\u6837\u5c31\u4f7f\u5f97\u8fd9\u4e9b\u4ee3\u7801\u53ef\u4ee5\u88ab\u7528\u5728\u5176\u4ed6\u7684\u4e0a\u4e0b\u6587\u4e2d\uff0c\u53ef\u80fd\u4e0e\u7ebf\u7a0b\u6709\u5173\uff0c\u4e5f\u53ef\u80fd\u4e0e\u7ebf\u7a0b\u65e0\u5173\u3002\u6bd4\u5982\uff0c\u4f60\u53ef\u4ee5\u901a\u8fc7 multiprocessing \u6a21\u5757\u5728\u4e00\u4e2a\u5355\u72ec\u7684\u8fdb\u7a0b\u4e2d\u6267\u884c\u4f60\u7684\u4ee3\u7801\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "import multiprocessing\nc = CountdownTask(5)\np = multiprocessing.Process(target=c.run)\np.start()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u518d\u6b21\u91cd\u7533\uff0c\u8fd9\u6bb5\u4ee3\u7801\u4ec5\u9002\u7528\u4e8e CountdownTask \u7c7b\u662f\u4ee5\u72ec\u7acb\u4e8e\u5b9e\u9645\u7684\u5e76\u53d1\u624b\u6bb5\uff08\u591a\u7ebf\u7a0b\u3001\u591a\u8fdb\u7a0b\u7b49\u7b49\uff09\u5b9e\u73b0\u7684\u60c5\u51b5\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 12.2 \u5224\u65ad\u7ebf\u7a0b\u662f\u5426\u5df2\u7ecf\u542f\u52a8\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u95ee\u9898\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4f60\u5df2\u7ecf\u542f\u52a8\u4e86\u4e00\u4e2a\u7ebf\u7a0b\uff0c\u4f46\u662f\u4f60\u60f3\u77e5\u9053\u5b83\u662f\u4e0d\u662f\u771f\u7684\u5df2\u7ecf\u5f00\u59cb\u8fd0\u884c\u4e86\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u89e3\u51b3\u65b9\u6848\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u7ebf\u7a0b\u7684\u4e00\u4e2a\u5173\u952e\u7279\u6027\u662f\u6bcf\u4e2a\u7ebf\u7a0b\u90fd\u662f\u72ec\u7acb\u8fd0\u884c\u4e14\u72b6\u6001\u4e0d\u53ef\u9884\u6d4b\u3002\u5982\u679c\u7a0b\u5e8f\u4e2d\u7684\u5176\u4ed6\u7ebf\u7a0b\u9700\u8981\u901a\u8fc7\u5224\u65ad\u67d0\u4e2a\u7ebf\u7a0b\u7684\u72b6\u6001\u6765\u786e\u5b9a\u81ea\u5df1\u4e0b\u4e00\u6b65\u7684\u64cd\u4f5c\uff0c\u8fd9\u65f6\u7ebf\u7a0b\u540c\u6b65\u95ee\u9898\u5c31\u4f1a\u53d8\u5f97\u975e\u5e38\u68d8\u624b\u3002\u4e3a\u4e86\u89e3\u51b3\u8fd9\u4e9b\u95ee\u9898\uff0c\u6211\u4eec\u9700\u8981\u4f7f\u7528 threading \u5e93\u4e2d\u7684 Event \u5bf9\u8c61\u3002\nEvent \u5bf9\u8c61\u5305\u542b\u4e00\u4e2a\u53ef\u7531\u7ebf\u7a0b\u8bbe\u7f6e\u7684\u4fe1\u53f7\u6807\u5fd7\uff0c\u5b83\u5141\u8bb8\u7ebf\u7a0b\u7b49\u5f85\u67d0\u4e9b\u4e8b\u4ef6\u7684\u53d1\u751f\u3002\u5728\u521d\u59cb\u60c5\u51b5\u4e0b\uff0cevent \u5bf9\u8c61\u4e2d\u7684\u4fe1\u53f7\u6807\u5fd7\u88ab\u8bbe\u7f6e\u4e3a\u5047\u3002\u5982\u679c\u6709\u7ebf\u7a0b\u7b49\u5f85\u4e00\u4e2a event \u5bf9\u8c61\uff0c\u800c\u8fd9\u4e2a event \u5bf9\u8c61\u7684\u6807\u5fd7\u4e3a\u5047\uff0c\u90a3\u4e48\u8fd9\u4e2a\u7ebf\u7a0b\u5c06\u4f1a\u88ab\u4e00\u76f4\u963b\u585e\u76f4\u81f3\u8be5\u6807\u5fd7\u4e3a\u771f\u3002\u4e00\u4e2a\u7ebf\u7a0b\u5982\u679c\u5c06\u4e00\u4e2a event \u5bf9\u8c61\u7684\u4fe1\u53f7\u6807\u5fd7\u8bbe\u7f6e\u4e3a\u771f\uff0c\u5b83\u5c06\u5524\u9192\u6240\u6709\u7b49\u5f85\u8fd9\u4e2a event \u5bf9\u8c61\u7684\u7ebf\u7a0b\u3002\u5982\u679c\u4e00\u4e2a\u7ebf\u7a0b\u7b49\u5f85\u4e00\u4e2a\u5df2\u7ecf\u88ab\u8bbe\u7f6e\u4e3a\u771f\u7684 event \u5bf9\u8c61\uff0c\u90a3\u4e48\u5b83\u5c06\u5ffd\u7565\u8fd9\u4e2a\u4e8b\u4ef6\uff0c\u7ee7\u7eed\u6267\u884c\u3002\n\u4e0b\u8fb9\u7684\u4ee3\u7801\u5c55\u793a\u4e86\u5982\u4f55\u4f7f\u7528 Event \u6765\u534f\u8c03\u7ebf\u7a0b\u7684\u542f\u52a8\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from threading import Thread, Event\nimport time\n\n# Code to execute in an independent thread\ndef countdown(n, started_evt):\n    print('countdown starting')\n    started_evt.set()\n    while n > 0:\n        print('T-minus', n)\n        n -= 1\n        time.sleep(5)\n\n# Create the event object that will be used to signal startup\nstarted_evt = Event()\n\n# Launch the thread and pass the startup event\nprint('Launching countdown')\nt = Thread(target=countdown, args=(10,started_evt))\nt.start()\n\n# Wait for the thread to start\nstarted_evt.wait()\nprint('countdown is running')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5f53\u4f60\u6267\u884c\u8fd9\u6bb5\u4ee3\u7801\uff0c\u201ccountdown is running\u201d \u603b\u662f\u663e\u793a\u5728 \u201ccountdown starting\u201d \u4e4b\u540e\u663e\u793a\u3002\u8fd9\u662f\u7531\u4e8e\u4f7f\u7528 event \u6765\u534f\u8c03\u7ebf\u7a0b\uff0c\u4f7f\u5f97\u4e3b\u7ebf\u7a0b\u8981\u7b49\u5230 countdown() \u51fd\u6570\u8f93\u51fa\u542f\u52a8\u4fe1\u606f\u540e\uff0c\u624d\u80fd\u7ee7\u7eed\u6267\u884c\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u8ba8\u8bba\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "event \u5bf9\u8c61\u6700\u597d\u5355\u6b21\u4f7f\u7528\uff0c\u5c31\u662f\u8bf4\uff0c\u4f60\u521b\u5efa\u4e00\u4e2a event \u5bf9\u8c61\uff0c\u8ba9\u67d0\u4e2a\u7ebf\u7a0b\u7b49\u5f85\u8fd9\u4e2a\u5bf9\u8c61\uff0c\u4e00\u65e6\u8fd9\u4e2a\u5bf9\u8c61\u88ab\u8bbe\u7f6e\u4e3a\u771f\uff0c\u4f60\u5c31\u5e94\u8be5\u4e22\u5f03\u5b83\u3002\u5c3d\u7ba1\u53ef\u4ee5\u901a\u8fc7 clear() \u65b9\u6cd5\u6765\u91cd\u7f6e event \u5bf9\u8c61\uff0c\u4f46\u662f\u5f88\u96be\u786e\u4fdd\u5b89\u5168\u5730\u6e05\u7406 event \u5bf9\u8c61\u5e76\u5bf9\u5b83\u91cd\u65b0\u8d4b\u503c\u3002\u5f88\u53ef\u80fd\u4f1a\u53d1\u751f\u9519\u8fc7\u4e8b\u4ef6\u3001\u6b7b\u9501\u6216\u8005\u5176\u4ed6\u95ee\u9898\uff08\u7279\u522b\u662f\uff0c\u4f60\u65e0\u6cd5\u4fdd\u8bc1\u91cd\u7f6e event \u5bf9\u8c61\u7684\u4ee3\u7801\u4f1a\u5728\u7ebf\u7a0b\u518d\u6b21\u7b49\u5f85\u8fd9\u4e2a event \u5bf9\u8c61\u4e4b\u524d\u6267\u884c\uff09\u3002\u5982\u679c\u4e00\u4e2a\u7ebf\u7a0b\u9700\u8981\u4e0d\u505c\u5730\u91cd\u590d\u4f7f\u7528 event \u5bf9\u8c61\uff0c\u4f60\u6700\u597d\u4f7f\u7528 Condition \u5bf9\u8c61\u6765\u4ee3\u66ff\u3002\u4e0b\u9762\u7684\u4ee3\u7801\u4f7f\u7528 Condition \u5bf9\u8c61\u5b9e\u73b0\u4e86\u4e00\u4e2a\u5468\u671f\u5b9a\u65f6\u5668\uff0c\u6bcf\u5f53\u5b9a\u65f6\u5668\u8d85\u65f6\u7684\u65f6\u5019\uff0c\u5176\u4ed6\u7ebf\u7a0b\u90fd\u53ef\u4ee5\u76d1\u6d4b\u5230\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "import threading\nimport time\n\nclass PeriodicTimer:\n    def __init__(self, interval):\n        self._interval = interval\n        self._flag = 0\n        self._cv = threading.Condition()\n\n    def start(self):\n        t = threading.Thread(target=self.run)\n        t.daemon = True\n\n        t.start()\n\n    def run(self):\n        '''\n        Run the timer and notify waiting threads after each interval\n        '''\n        while True:\n            time.sleep(self._interval)\n            with self._cv:\n                 self._flag ^= 1\n                 self._cv.notify_all()\n\n    def wait_for_tick(self):\n        '''\n        Wait for the next tick of the timer\n        '''\n        with self._cv:\n            last_flag = self._flag\n            while last_flag == self._flag:\n                self._cv.wait()\n\n# Example use of the timer\nptimer = PeriodicTimer(5)\nptimer.start()\n\n# Two threads that synchronize on the timer\ndef countdown(nticks):\n    while nticks > 0:\n        ptimer.wait_for_tick()\n        print('T-minus', nticks)\n        nticks -= 1\n\ndef countup(last):\n    n = 0\n    while n < last:\n        ptimer.wait_for_tick()\n        print('Counting', n)\n        n += 1\n\nthreading.Thread(target=countdown, args=(10,)).start()\nthreading.Thread(target=countup, args=(5,)).start()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "event\u5bf9\u8c61\u7684\u4e00\u4e2a\u91cd\u8981\u7279\u70b9\u662f\u5f53\u5b83\u88ab\u8bbe\u7f6e\u4e3a\u771f\u65f6\u4f1a\u5524\u9192\u6240\u6709\u7b49\u5f85\u5b83\u7684\u7ebf\u7a0b\u3002\u5982\u679c\u4f60\u53ea\u60f3\u5524\u9192\u5355\u4e2a\u7ebf\u7a0b\uff0c\u6700\u597d\u662f\u4f7f\u7528\u4fe1\u53f7\u91cf\u6216\u8005 Condition \u5bf9\u8c61\u6765\u66ff\u4ee3\u3002\u8003\u8651\u4e00\u4e0b\u8fd9\u6bb5\u4f7f\u7528\u4fe1\u53f7\u91cf\u5b9e\u73b0\u7684\u4ee3\u7801\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# Worker thread\ndef worker(n, sema):\n    # Wait to be signaled\n    sema.acquire()\n\n    # Do some work\n    print('Working', n)\n\n# Create some threads\nsema = threading.Semaphore(0)\nnworkers = 10\nfor n in range(nworkers):\n    t = threading.Thread(target=worker, args=(n, sema,))\n    t.start()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u8fd0\u884c\u4e0a\u8fb9\u7684\u4ee3\u7801\u5c06\u4f1a\u542f\u52a8\u4e00\u4e2a\u7ebf\u7a0b\u6c60\uff0c\u4f46\u662f\u5e76\u6ca1\u6709\u4ec0\u4e48\u4e8b\u60c5\u53d1\u751f\u3002\u8fd9\u662f\u56e0\u4e3a\u6240\u6709\u7684\u7ebf\u7a0b\u90fd\u5728\u7b49\u5f85\u83b7\u53d6\u4fe1\u53f7\u91cf\u3002\u6bcf\u6b21\u4fe1\u53f7\u91cf\u88ab\u91ca\u653e\uff0c\u53ea\u6709\u4e00\u4e2a\u7ebf\u7a0b\u4f1a\u88ab\u5524\u9192\u5e76\u6267\u884c\uff0c\u793a\u4f8b\u5982\u4e0b\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "sema.release()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "sema.release()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u7f16\u5199\u6d89\u53ca\u5230\u5927\u91cf\u7684\u7ebf\u7a0b\u95f4\u540c\u6b65\u95ee\u9898\u7684\u4ee3\u7801\u4f1a\u8ba9\u4f60\u75db\u4e0d\u6b32\u751f\u3002\u6bd4\u8f83\u5408\u9002\u7684\u65b9\u5f0f\u662f\u4f7f\u7528\u961f\u5217\u6765\u8fdb\u884c\u7ebf\u7a0b\u95f4\u901a\u4fe1\u6216\u8005\u6bcf\u4e2a\u628a\u7ebf\u7a0b\u5f53\u4f5c\u4e00\u4e2aActor\uff0c\u5229\u7528Actor\u6a21\u578b\u6765\u63a7\u5236\u5e76\u53d1\u3002\u4e0b\u4e00\u8282\u5c06\u4f1a\u4ecb\u7ecd\u5230\u961f\u5217\uff0c\u800cActor\u6a21\u578b\u5c06\u572812.10\u8282\u4ecb\u7ecd\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 12.3 \u7ebf\u7a0b\u95f4\u901a\u4fe1\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u95ee\u9898\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4f60\u7684\u7a0b\u5e8f\u4e2d\u6709\u591a\u4e2a\u7ebf\u7a0b\uff0c\u4f60\u9700\u8981\u5728\u8fd9\u4e9b\u7ebf\u7a0b\u4e4b\u95f4\u5b89\u5168\u5730\u4ea4\u6362\u4fe1\u606f\u6216\u6570\u636e"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u89e3\u51b3\u65b9\u6848\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4ece\u4e00\u4e2a\u7ebf\u7a0b\u5411\u53e6\u4e00\u4e2a\u7ebf\u7a0b\u53d1\u9001\u6570\u636e\u6700\u5b89\u5168\u7684\u65b9\u5f0f\u53ef\u80fd\u5c31\u662f\u4f7f\u7528 queue \u5e93\u4e2d\u7684\u961f\u5217\u4e86\u3002\u521b\u5efa\u4e00\u4e2a\u88ab\u591a\u4e2a\u7ebf\u7a0b\u5171\u4eab\u7684 Queue \u5bf9\u8c61\uff0c\u8fd9\u4e9b\u7ebf\u7a0b\u901a\u8fc7\u4f7f\u7528 put() \u548c get() \u64cd\u4f5c\u6765\u5411\u961f\u5217\u4e2d\u6dfb\u52a0\u6216\u8005\u5220\u9664\u5143\u7d20\u3002\n\u4f8b\u5982\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from queue import Queue\nfrom threading import Thread\n\n# A thread that produces data\ndef producer(out_q):\n    while True:\n        # Produce some data\n        ...\n        out_q.put(data)\n\n# A thread that consumes data\ndef consumer(in_q):\n    while True:\n# Get some data\n        data = in_q.get()\n        # Process the data\n        ...\n\n# Create the shared queue and launch both threads\nq = Queue()\nt1 = Thread(target=consumer, args=(q,))\nt2 = Thread(target=producer, args=(q,))\nt1.start()\nt2.start()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Queue \u5bf9\u8c61\u5df2\u7ecf\u5305\u542b\u4e86\u5fc5\u8981\u7684\u9501\uff0c\u6240\u4ee5\u4f60\u53ef\u4ee5\u901a\u8fc7\u5b83\u5728\u591a\u4e2a\u7ebf\u7a0b\u95f4\u591a\u5b89\u5168\u5730\u5171\u4eab\u6570\u636e\u3002\n\u5f53\u4f7f\u7528\u961f\u5217\u65f6\uff0c\u534f\u8c03\u751f\u4ea7\u8005\u548c\u6d88\u8d39\u8005\u7684\u5173\u95ed\u95ee\u9898\u53ef\u80fd\u4f1a\u6709\u4e00\u4e9b\u9ebb\u70e6\u3002\u4e00\u4e2a\u901a\u7528\u7684\u89e3\u51b3\u65b9\u6cd5\u662f\u5728\u961f\u5217\u4e2d\u653e\u7f6e\u4e00\u4e2a\u7279\u6b8a\u7684\u503c\uff0c\u5f53\u6d88\u8d39\u8005\u8bfb\u5230\u8fd9\u4e2a\u503c\u7684\u65f6\u5019\uff0c\u7ec8\u6b62\u6267\u884c\u3002\u4f8b\u5982\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from queue import Queue\nfrom threading import Thread\n\n# Object that signals shutdown\n_sentinel = object()\n\n# A thread that produces data\ndef producer(out_q):\n    while running:\n        # Produce some data\n        ...\n        out_q.put(data)\n\n    # Put the sentinel on the queue to indicate completion\n    out_q.put(_sentinel)\n\n# A thread that consumes data\ndef consumer(in_q):\n    while True:\n        # Get some data\n        data = in_q.get()\n\n        # Check for termination\n        if data is _sentinel:\n            in_q.put(_sentinel)\n            break\n\n        # Process the data\n        ..."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u672c\u4f8b\u4e2d\u6709\u4e00\u4e2a\u7279\u6b8a\u7684\u5730\u65b9\uff1a\u6d88\u8d39\u8005\u5728\u8bfb\u5230\u8fd9\u4e2a\u7279\u6b8a\u503c\u4e4b\u540e\u7acb\u5373\u53c8\u628a\u5b83\u653e\u56de\u5230\u961f\u5217\u4e2d\uff0c\u5c06\u4e4b\u4f20\u9012\u4e0b\u53bb\u3002\u8fd9\u6837\uff0c\u6240\u6709\u76d1\u542c\u8fd9\u4e2a\u961f\u5217\u7684\u6d88\u8d39\u8005\u7ebf\u7a0b\u5c31\u53ef\u4ee5\u5168\u90e8\u5173\u95ed\u4e86\u3002\n\u5c3d\u7ba1\u961f\u5217\u662f\u6700\u5e38\u89c1\u7684\u7ebf\u7a0b\u95f4\u901a\u4fe1\u673a\u5236\uff0c\u4f46\u662f\u4ecd\u7136\u53ef\u4ee5\u81ea\u5df1\u901a\u8fc7\u521b\u5efa\u81ea\u5df1\u7684\u6570\u636e\u7ed3\u6784\u5e76\u6dfb\u52a0\u6240\u9700\u7684\u9501\u548c\u540c\u6b65\u673a\u5236\u6765\u5b9e\u73b0\u7ebf\u7a0b\u95f4\u901a\u4fe1\u3002\u6700\u5e38\u89c1\u7684\u65b9\u6cd5\u662f\u4f7f\u7528 Condition \u53d8\u91cf\u6765\u5305\u88c5\u4f60\u7684\u6570\u636e\u7ed3\u6784\u3002\u4e0b\u8fb9\u8fd9\u4e2a\u4f8b\u5b50\u6f14\u793a\u4e86\u5982\u4f55\u521b\u5efa\u4e00\u4e2a\u7ebf\u7a0b\u5b89\u5168\u7684\u4f18\u5148\u7ea7\u961f\u5217\uff0c\u5982\u540c1.5\u8282\u4e2d\u4ecb\u7ecd\u7684\u90a3\u6837\u3002"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "import heapq\nimport threading\n\nclass PriorityQueue:\n    def __init__(self):\n        self._queue = []\n        self._count = 0\n        self._cv = threading.Condition()\n    def put(self, item, priority):\n        with self._cv:\n            heapq.heappush(self._queue, (-priority, self._count, item))\n            self._count += 1\n            self._cv.notify()\n\n    def get(self):\n        with self._cv:\n            while len(self._queue) == 0:\n                self._cv.wait()\n            return heapq.heappop(self._queue)[-1]"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4f7f\u7528\u961f\u5217\u6765\u8fdb\u884c\u7ebf\u7a0b\u95f4\u901a\u4fe1\u662f\u4e00\u4e2a\u5355\u5411\u3001\u4e0d\u786e\u5b9a\u7684\u8fc7\u7a0b\u3002\u901a\u5e38\u60c5\u51b5\u4e0b\uff0c\u4f60\u6ca1\u6709\u529e\u6cd5\u77e5\u9053\u63a5\u6536\u6570\u636e\u7684\u7ebf\u7a0b\u662f\u4ec0\u4e48\u65f6\u5019\u63a5\u6536\u5230\u7684\u6570\u636e\u5e76\u5f00\u59cb\u5de5\u4f5c\u7684\u3002\u4e0d\u8fc7\u961f\u5217\u5bf9\u8c61\u63d0\u4f9b\u4e00\u4e9b\u57fa\u672c\u5b8c\u6210\u7684\u7279\u6027\uff0c\u6bd4\u5982\u4e0b\u8fb9\u8fd9\u4e2a\u4f8b\u5b50\u4e2d\u7684 task_done() \u548c join() \uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from queue import Queue\nfrom threading import Thread\n\n# A thread that produces data\ndef producer(out_q):\n    while running:\n        # Produce some data\n        ...\n        out_q.put(data)\n\n# A thread that consumes data\ndef consumer(in_q):\n    while True:\n        # Get some data\n        data = in_q.get()\n\n        # Process the data\n        ...\n        # Indicate completion\n        in_q.task_done()\n\n# Create the shared queue and launch both threads\nq = Queue()\nt1 = Thread(target=consumer, args=(q,))\nt2 = Thread(target=producer, args=(q,))\nt1.start()\nt2.start()\n\n# Wait for all produced items to be consumed\nq.join()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5982\u679c\u4e00\u4e2a\u7ebf\u7a0b\u9700\u8981\u5728\u4e00\u4e2a\u201c\u6d88\u8d39\u8005\u201d\u7ebf\u7a0b\u5904\u7406\u5b8c\u7279\u5b9a\u7684\u6570\u636e\u9879\u65f6\u7acb\u5373\u5f97\u5230\u901a\u77e5\uff0c\u4f60\u53ef\u4ee5\u628a\u8981\u53d1\u9001\u7684\u6570\u636e\u548c\u4e00\u4e2a Event \u653e\u5230\u4e00\u8d77\u4f7f\u7528\uff0c\u8fd9\u6837\u201c\u751f\u4ea7\u8005\u201d\u5c31\u53ef\u4ee5\u901a\u8fc7\u8fd9\u4e2aEvent\u5bf9\u8c61\u6765\u76d1\u6d4b\u5904\u7406\u7684\u8fc7\u7a0b\u4e86\u3002\u793a\u4f8b\u5982\u4e0b\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from queue import Queue\nfrom threading import Thread, Event\n\n# A thread that produces data\ndef producer(out_q):\n    while running:\n        # Produce some data\n        ...\n        # Make an (data, event) pair and hand it to the consumer\n        evt = Event()\n        out_q.put((data, evt))\n        ...\n        # Wait for the consumer to process the item\n        evt.wait()\n\n# A thread that consumes data\ndef consumer(in_q):\n    while True:\n        # Get some data\n        data, evt = in_q.get()\n        # Process the data\n        ...\n        # Indicate completion\n        evt.set()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u8ba8\u8bba\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u57fa\u4e8e\u7b80\u5355\u961f\u5217\u7f16\u5199\u591a\u7ebf\u7a0b\u7a0b\u5e8f\u5728\u591a\u6570\u60c5\u51b5\u4e0b\u662f\u4e00\u4e2a\u6bd4\u8f83\u660e\u667a\u7684\u9009\u62e9\u3002\u4ece\u7ebf\u7a0b\u5b89\u5168\u961f\u5217\u7684\u5e95\u5c42\u5b9e\u73b0\u6765\u770b\uff0c\u4f60\u65e0\u9700\u5728\u4f60\u7684\u4ee3\u7801\u4e2d\u4f7f\u7528\u9501\u548c\u5176\u4ed6\u5e95\u5c42\u7684\u540c\u6b65\u673a\u5236\uff0c\u8fd9\u4e9b\u53ea\u4f1a\u628a\u4f60\u7684\u7a0b\u5e8f\u5f04\u5f97\u4e71\u4e03\u516b\u7cdf\u3002\u6b64\u5916\uff0c\u4f7f\u7528\u961f\u5217\u8fd9\u79cd\u57fa\u4e8e\u6d88\u606f\u7684\u901a\u4fe1\u673a\u5236\u53ef\u4ee5\u88ab\u6269\u5c55\u5230\u66f4\u5927\u7684\u5e94\u7528\u8303\u7574\uff0c\u6bd4\u5982\uff0c\u4f60\u53ef\u4ee5\u628a\u4f60\u7684\u7a0b\u5e8f\u653e\u5165\u591a\u4e2a\u8fdb\u7a0b\u751a\u81f3\u662f\u5206\u5e03\u5f0f\u7cfb\u7edf\u800c\u65e0\u9700\u6539\u53d8\u5e95\u5c42\u7684\u961f\u5217\u7ed3\u6784\u3002\n\u4f7f\u7528\u7ebf\u7a0b\u961f\u5217\u6709\u4e00\u4e2a\u8981\u6ce8\u610f\u7684\u95ee\u9898\u662f\uff0c\u5411\u961f\u5217\u4e2d\u6dfb\u52a0\u6570\u636e\u9879\u65f6\u5e76\u4e0d\u4f1a\u590d\u5236\u6b64\u6570\u636e\u9879\uff0c\u7ebf\u7a0b\u95f4\u901a\u4fe1\u5b9e\u9645\u4e0a\u662f\u5728\u7ebf\u7a0b\u95f4\u4f20\u9012\u5bf9\u8c61\u5f15\u7528\u3002\u5982\u679c\u4f60\u62c5\u5fc3\u5bf9\u8c61\u7684\u5171\u4eab\u72b6\u6001\uff0c\u90a3\u4f60\u6700\u597d\u53ea\u4f20\u9012\u4e0d\u53ef\u4fee\u6539\u7684\u6570\u636e\u7ed3\u6784\uff08\u5982\uff1a\u6574\u578b\u3001\u5b57\u7b26\u4e32\u6216\u8005\u5143\u7ec4\uff09\u6216\u8005\u4e00\u4e2a\u5bf9\u8c61\u7684\u6df1\u62f7\u8d1d\u3002\u4f8b\u5982\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from queue import Queue\nfrom threading import Thread\nimport copy\n\n# A thread that produces data\ndef producer(out_q):\n    while True:\n        # Produce some data\n        ...\n        out_q.put(copy.deepcopy(data))\n\n# A thread that consumes data\ndef consumer(in_q):\n    while True:\n        # Get some data\n        data = in_q.get()\n        # Process the data\n        ..."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Queue \u5bf9\u8c61\u63d0\u4f9b\u4e00\u4e9b\u5728\u5f53\u524d\u4e0a\u4e0b\u6587\u5f88\u6709\u7528\u7684\u9644\u52a0\u7279\u6027\u3002\u6bd4\u5982\u5728\u521b\u5efa Queue \u5bf9\u8c61\u65f6\u63d0\u4f9b\u53ef\u9009\u7684 size \u53c2\u6570\u6765\u9650\u5236\u53ef\u4ee5\u6dfb\u52a0\u5230\u961f\u5217\u4e2d\u7684\u5143\u7d20\u6570\u91cf\u3002\u5bf9\u4e8e\u201c\u751f\u4ea7\u8005\u201d\u4e0e\u201c\u6d88\u8d39\u8005\u201d\u901f\u5ea6\u6709\u5dee\u5f02\u7684\u60c5\u51b5\uff0c\u4e3a\u961f\u5217\u4e2d\u7684\u5143\u7d20\u6570\u91cf\u6dfb\u52a0\u4e0a\u9650\u662f\u6709\u610f\u4e49\u7684\u3002\u6bd4\u5982\uff0c\u4e00\u4e2a\u201c\u751f\u4ea7\u8005\u201d\u4ea7\u751f\u9879\u76ee\u7684\u901f\u5ea6\u6bd4\u201c\u6d88\u8d39\u8005\u201d \u201c\u6d88\u8d39\u201d\u7684\u901f\u5ea6\u5feb\uff0c\u90a3\u4e48\u4f7f\u7528\u56fa\u5b9a\u5927\u5c0f\u7684\u961f\u5217\u5c31\u53ef\u4ee5\u5728\u961f\u5217\u5df2\u6ee1\u7684\u65f6\u5019\u963b\u585e\u961f\u5217\uff0c\u4ee5\u514d\u672a\u9884\u671f\u7684\u8fde\u9501\u6548\u5e94\u6269\u6563\u6574\u4e2a\u7a0b\u5e8f\u9020\u6210\u6b7b\u9501\u6216\u8005\u7a0b\u5e8f\u8fd0\u884c\u5931\u5e38\u3002\u5728\u901a\u4fe1\u7684\u7ebf\u7a0b\u4e4b\u95f4\u8fdb\u884c\u201c\u6d41\u91cf\u63a7\u5236\u201d\u662f\u4e00\u4e2a\u770b\u8d77\u6765\u5bb9\u6613\u5b9e\u73b0\u8d77\u6765\u56f0\u96be\u7684\u95ee\u9898\u3002\u5982\u679c\u4f60\u53d1\u73b0\u81ea\u5df1\u66fe\u7ecf\u8bd5\u56fe\u901a\u8fc7\u6446\u5f04\u961f\u5217\u5927\u5c0f\u6765\u89e3\u51b3\u4e00\u4e2a\u95ee\u9898\uff0c\u8fd9\u4e5f\u8bb8\u5c31\u6807\u5fd7\u7740\u4f60\u7684\u7a0b\u5e8f\u53ef\u80fd\u5b58\u5728\u8106\u5f31\u8bbe\u8ba1\u6216\u8005\u56fa\u6709\u7684\u53ef\u4f38\u7f29\u95ee\u9898\u3002\nget() \u548c put() \u65b9\u6cd5\u90fd\u652f\u6301\u975e\u963b\u585e\u65b9\u5f0f\u548c\u8bbe\u5b9a\u8d85\u65f6\uff0c\u4f8b\u5982\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "import queue\nq = queue.Queue()\n\ntry:\n    data = q.get(block=False)\nexcept queue.Empty:\n    ...\n\ntry:\n    q.put(item, block=False)\nexcept queue.Full:\n    ...\n\ntry:\n    data = q.get(timeout=5.0)\nexcept queue.Empty:\n    ..."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u8fd9\u4e9b\u64cd\u4f5c\u90fd\u53ef\u4ee5\u7528\u6765\u907f\u514d\u5f53\u6267\u884c\u67d0\u4e9b\u7279\u5b9a\u961f\u5217\u64cd\u4f5c\u65f6\u53d1\u751f\u65e0\u9650\u963b\u585e\u7684\u60c5\u51b5\uff0c\u6bd4\u5982\uff0c\u4e00\u4e2a\u975e\u963b\u585e\u7684 put() \u65b9\u6cd5\u548c\u4e00\u4e2a\u56fa\u5b9a\u5927\u5c0f\u7684\u961f\u5217\u4e00\u8d77\u4f7f\u7528\uff0c\u8fd9\u6837\u5f53\u961f\u5217\u5df2\u6ee1\u65f6\u5c31\u53ef\u4ee5\u6267\u884c\u4e0d\u540c\u7684\u4ee3\u7801\u3002\u6bd4\u5982\u8f93\u51fa\u4e00\u6761\u65e5\u5fd7\u4fe1\u606f\u5e76\u4e22\u5f03\u3002"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "def producer(q):\n    ...\n    try:\n        q.put(item, block=False)\n    except queue.Full:\n        log.warning('queued item %r discarded!', item)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5982\u679c\u4f60\u8bd5\u56fe\u8ba9\u6d88\u8d39\u8005\u7ebf\u7a0b\u5728\u6267\u884c\u50cf q.get() \u8fd9\u6837\u7684\u64cd\u4f5c\u65f6\uff0c\u8d85\u65f6\u81ea\u52a8\u7ec8\u6b62\u4ee5\u4fbf\u68c0\u67e5\u7ec8\u6b62\u6807\u5fd7\uff0c\u4f60\u5e94\u8be5\u4f7f\u7528 q.get() \u7684\u53ef\u9009\u53c2\u6570 timeout \uff0c\u5982\u4e0b\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "_running = True\n\ndef consumer(q):\n    while _running:\n        try:\n            item = q.get(timeout=5.0)\n            # Process item\n            ...\n        except queue.Empty:\n            pass"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u6700\u540e\uff0c\u6709 q.qsize() \uff0c q.full() \uff0c q.empty() \u7b49\u5b9e\u7528\u65b9\u6cd5\u53ef\u4ee5\u83b7\u53d6\u4e00\u4e2a\u961f\u5217\u7684\u5f53\u524d\u5927\u5c0f\u548c\u72b6\u6001\u3002\u4f46\u8981\u6ce8\u610f\uff0c\u8fd9\u4e9b\u65b9\u6cd5\u90fd\u4e0d\u662f\u7ebf\u7a0b\u5b89\u5168\u7684\u3002\u53ef\u80fd\u4f60\u5bf9\u4e00\u4e2a\u961f\u5217\u4f7f\u7528 empty() \u5224\u65ad\u51fa\u8fd9\u4e2a\u961f\u5217\u4e3a\u7a7a\uff0c\u4f46\u540c\u65f6\u53e6\u5916\u4e00\u4e2a\u7ebf\u7a0b\u53ef\u80fd\u5df2\u7ecf\u5411\u8fd9\u4e2a\u961f\u5217\u4e2d\u63d2\u5165\u4e00\u4e2a\u6570\u636e\u9879\u3002\u6240\u4ee5\uff0c\u4f60\u6700\u597d\u4e0d\u8981\u5728\u4f60\u7684\u4ee3\u7801\u4e2d\u4f7f\u7528\u8fd9\u4e9b\u65b9\u6cd5\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 12.4 \u7ed9\u5173\u952e\u90e8\u5206\u52a0\u9501\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u95ee\u9898\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4f60\u9700\u8981\u5bf9\u591a\u7ebf\u7a0b\u7a0b\u5e8f\u4e2d\u7684\u4e34\u754c\u533a\u52a0\u9501\u4ee5\u907f\u514d\u7ade\u4e89\u6761\u4ef6\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u89e3\u51b3\u65b9\u6848\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u8981\u5728\u591a\u7ebf\u7a0b\u7a0b\u5e8f\u4e2d\u5b89\u5168\u4f7f\u7528\u53ef\u53d8\u5bf9\u8c61\uff0c\u4f60\u9700\u8981\u4f7f\u7528 threading \u5e93\u4e2d\u7684 Lock \u5bf9\u8c61\uff0c\u5c31\u50cf\u4e0b\u8fb9\u8fd9\u4e2a\u4f8b\u5b50\u8fd9\u6837\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "import threading\n\nclass SharedCounter:\n    '''\n    A counter object that can be shared by multiple threads.\n    '''\n    def __init__(self, initial_value = 0):\n        self._value = initial_value\n        self._value_lock = threading.Lock()\n\n    def incr(self,delta=1):\n        '''\n        Increment the counter with locking\n        '''\n        with self._value_lock:\n             self._value += delta\n\n    def decr(self,delta=1):\n        '''\n        Decrement the counter with locking\n        '''\n        with self._value_lock:\n             self._value -= delta"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Lock \u5bf9\u8c61\u548c with \u8bed\u53e5\u5757\u4e00\u8d77\u4f7f\u7528\u53ef\u4ee5\u4fdd\u8bc1\u4e92\u65a5\u6267\u884c\uff0c\u5c31\u662f\u6bcf\u6b21\u53ea\u6709\u4e00\u4e2a\u7ebf\u7a0b\u53ef\u4ee5\u6267\u884c with \u8bed\u53e5\u5305\u542b\u7684\u4ee3\u7801\u5757\u3002with \u8bed\u53e5\u4f1a\u5728\u8fd9\u4e2a\u4ee3\u7801\u5757\u6267\u884c\u524d\u81ea\u52a8\u83b7\u53d6\u9501\uff0c\u5728\u6267\u884c\u7ed3\u675f\u540e\u81ea\u52a8\u91ca\u653e\u9501\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u8ba8\u8bba\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u7ebf\u7a0b\u8c03\u5ea6\u672c\u8d28\u4e0a\u662f\u4e0d\u786e\u5b9a\u7684\uff0c\u56e0\u6b64\uff0c\u5728\u591a\u7ebf\u7a0b\u7a0b\u5e8f\u4e2d\u9519\u8bef\u5730\u4f7f\u7528\u9501\u673a\u5236\u53ef\u80fd\u4f1a\u5bfc\u81f4\u968f\u673a\u6570\u636e\u635f\u574f\u6216\u8005\u5176\u4ed6\u7684\u5f02\u5e38\u884c\u4e3a\uff0c\u6211\u4eec\u79f0\u4e4b\u4e3a\u7ade\u4e89\u6761\u4ef6\u3002\u4e3a\u4e86\u907f\u514d\u7ade\u4e89\u6761\u4ef6\uff0c\u6700\u597d\u53ea\u5728\u4e34\u754c\u533a\uff08\u5bf9\u4e34\u754c\u8d44\u6e90\u8fdb\u884c\u64cd\u4f5c\u7684\u90a3\u90e8\u5206\u4ee3\u7801\uff09\u4f7f\u7528\u9501\u3002\n\u5728\u4e00\u4e9b\u201c\u8001\u7684\u201d Python \u4ee3\u7801\u4e2d\uff0c\u663e\u5f0f\u83b7\u53d6\u548c\u91ca\u653e\u9501\u662f\u5f88\u5e38\u89c1\u7684\u3002\u4e0b\u8fb9\u662f\u4e00\u4e2a\u4e0a\u4e00\u4e2a\u4f8b\u5b50\u7684\u53d8\u79cd\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "import threading\n\nclass SharedCounter:\n    '''\n    A counter object that can be shared by multiple threads.\n    '''\n    def __init__(self, initial_value = 0):\n        self._value = initial_value\n        self._value_lock = threading.Lock()\n\n    def incr(self,delta=1):\n        '''\n        Increment the counter with locking\n        '''\n        self._value_lock.acquire()\n        self._value += delta\n        self._value_lock.release()\n\n    def decr(self,delta=1):\n        '''\n        Decrement the counter with locking\n        '''\n        self._value_lock.acquire()\n        self._value -= delta\n        self._value_lock.release()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u76f8\u6bd4\u4e8e\u8fd9\u79cd\u663e\u5f0f\u8c03\u7528\u7684\u65b9\u6cd5\uff0cwith \u8bed\u53e5\u66f4\u52a0\u4f18\u96c5\uff0c\u4e5f\u66f4\u4e0d\u5bb9\u6613\u51fa\u9519\uff0c\u7279\u522b\u662f\u7a0b\u5e8f\u5458\u53ef\u80fd\u4f1a\u5fd8\u8bb0\u8c03\u7528 release() \u65b9\u6cd5\u6216\u8005\u7a0b\u5e8f\u5728\u83b7\u5f97\u9501\u4e4b\u540e\u4ea7\u751f\u5f02\u5e38\u8fd9\u4e24\u79cd\u60c5\u51b5\uff08\u4f7f\u7528 with \u8bed\u53e5\u53ef\u4ee5\u4fdd\u8bc1\u5728\u8fd9\u4e24\u79cd\u60c5\u51b5\u4e0b\u4ecd\u80fd\u6b63\u786e\u91ca\u653e\u9501\uff09\u3002\n\u4e3a\u4e86\u907f\u514d\u51fa\u73b0\u6b7b\u9501\u7684\u60c5\u51b5\uff0c\u4f7f\u7528\u9501\u673a\u5236\u7684\u7a0b\u5e8f\u5e94\u8be5\u8bbe\u5b9a\u4e3a\u6bcf\u4e2a\u7ebf\u7a0b\u4e00\u6b21\u53ea\u5141\u8bb8\u83b7\u53d6\u4e00\u4e2a\u9501\u3002\u5982\u679c\u4e0d\u80fd\u8fd9\u6837\u505a\u7684\u8bdd\uff0c\u4f60\u5c31\u9700\u8981\u66f4\u9ad8\u7ea7\u7684\u6b7b\u9501\u907f\u514d\u673a\u5236\uff0c\u6211\u4eec\u5c06\u572812.5\u8282\u4ecb\u7ecd\u3002\n\u5728 threading \u5e93\u4e2d\u8fd8\u63d0\u4f9b\u4e86\u5176\u4ed6\u7684\u540c\u6b65\u539f\u8bed\uff0c\u6bd4\u5982 RLock \u548c Semaphore \u5bf9\u8c61\u3002\u4f46\u662f\u6839\u636e\u4ee5\u5f80\u7ecf\u9a8c\uff0c\u8fd9\u4e9b\u539f\u8bed\u662f\u7528\u4e8e\u4e00\u4e9b\u7279\u6b8a\u7684\u60c5\u51b5\uff0c\u5982\u679c\u4f60\u53ea\u662f\u9700\u8981\u7b80\u5355\u5730\u5bf9\u53ef\u53d8\u5bf9\u8c61\u8fdb\u884c\u9501\u5b9a\uff0c\u90a3\u5c31\u4e0d\u5e94\u8be5\u4f7f\u7528\u5b83\u4eec\u3002\u4e00\u4e2a RLock \uff08\u53ef\u91cd\u5165\u9501\uff09\u53ef\u4ee5\u88ab\u540c\u4e00\u4e2a\u7ebf\u7a0b\u591a\u6b21\u83b7\u53d6\uff0c\u4e3b\u8981\u7528\u6765\u5b9e\u73b0\u57fa\u4e8e\u76d1\u6d4b\u5bf9\u8c61\u6a21\u5f0f\u7684\u9501\u5b9a\u548c\u540c\u6b65\u3002\u5728\u4f7f\u7528\u8fd9\u79cd\u9501\u7684\u60c5\u51b5\u4e0b\uff0c\u5f53\u9501\u88ab\u6301\u6709\u65f6\uff0c\u53ea\u6709\u4e00\u4e2a\u7ebf\u7a0b\u53ef\u4ee5\u4f7f\u7528\u5b8c\u6574\u7684\u51fd\u6570\u6216\u8005\u7c7b\u4e2d\u7684\u65b9\u6cd5\u3002\u6bd4\u5982\uff0c\u4f60\u53ef\u4ee5\u5b9e\u73b0\u4e00\u4e2a\u8fd9\u6837\u7684 SharedCounter \u7c7b\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "import threading\n\nclass SharedCounter:\n    '''\n    A counter object that can be shared by multiple threads.\n    '''\n    _lock = threading.RLock()\n    def __init__(self, initial_value = 0):\n        self._value = initial_value\n\n    def incr(self,delta=1):\n        '''\n        Increment the counter with locking\n        '''\n        with SharedCounter._lock:\n            self._value += delta\n\n    def decr(self,delta=1):\n        '''\n        Decrement the counter with locking\n        '''\n        with SharedCounter._lock:\n             self.incr(-delta)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5728\u4e0a\u8fb9\u8fd9\u4e2a\u4f8b\u5b50\u4e2d\uff0c\u6ca1\u6709\u5bf9\u6bcf\u4e00\u4e2a\u5b9e\u4f8b\u4e2d\u7684\u53ef\u53d8\u5bf9\u8c61\u52a0\u9501\uff0c\u53d6\u800c\u4ee3\u4e4b\u7684\u662f\u4e00\u4e2a\u88ab\u6240\u6709\u5b9e\u4f8b\u5171\u4eab\u7684\u7c7b\u7ea7\u9501\u3002\u8fd9\u4e2a\u9501\u7528\u6765\u540c\u6b65\u7c7b\u65b9\u6cd5\uff0c\u5177\u4f53\u6765\u8bf4\u5c31\u662f\uff0c\u8fd9\u4e2a\u9501\u53ef\u4ee5\u4fdd\u8bc1\u4e00\u6b21\u53ea\u6709\u4e00\u4e2a\u7ebf\u7a0b\u53ef\u4ee5\u8c03\u7528\u8fd9\u4e2a\u7c7b\u65b9\u6cd5\u3002\u4e0d\u8fc7\uff0c\u4e0e\u4e00\u4e2a\u6807\u51c6\u7684\u9501\u4e0d\u540c\u7684\u662f\uff0c\u5df2\u7ecf\u6301\u6709\u8fd9\u4e2a\u9501\u7684\u65b9\u6cd5\u5728\u8c03\u7528\u540c\u6837\u4f7f\u7528\u8fd9\u4e2a\u9501\u7684\u65b9\u6cd5\u65f6\uff0c\u65e0\u9700\u518d\u6b21\u83b7\u53d6\u9501\u3002\u6bd4\u5982 decr \u65b9\u6cd5\u3002\n\u8fd9\u79cd\u5b9e\u73b0\u65b9\u5f0f\u7684\u4e00\u4e2a\u7279\u70b9\u662f\uff0c\u65e0\u8bba\u8fd9\u4e2a\u7c7b\u6709\u591a\u5c11\u4e2a\u5b9e\u4f8b\u90fd\u53ea\u7528\u4e00\u4e2a\u9501\u3002\u56e0\u6b64\u5728\u9700\u8981\u5927\u91cf\u4f7f\u7528\u8ba1\u6570\u5668\u7684\u60c5\u51b5\u4e0b\u5185\u5b58\u6548\u7387\u66f4\u9ad8\u3002\u4e0d\u8fc7\u8fd9\u6837\u505a\u4e5f\u6709\u7f3a\u70b9\uff0c\u5c31\u662f\u5728\u7a0b\u5e8f\u4e2d\u4f7f\u7528\u5927\u91cf\u7ebf\u7a0b\u5e76\u9891\u7e41\u66f4\u65b0\u8ba1\u6570\u5668\u65f6\u4f1a\u6709\u4e89\u7528\u9501\u7684\u95ee\u9898\u3002\n\u4fe1\u53f7\u91cf\u5bf9\u8c61\u662f\u4e00\u4e2a\u5efa\u7acb\u5728\u5171\u4eab\u8ba1\u6570\u5668\u57fa\u7840\u4e0a\u7684\u540c\u6b65\u539f\u8bed\u3002\u5982\u679c\u8ba1\u6570\u5668\u4e0d\u4e3a0\uff0cwith \u8bed\u53e5\u5c06\u8ba1\u6570\u5668\u51cf1\uff0c\u7ebf\u7a0b\u88ab\u5141\u8bb8\u6267\u884c\u3002with \u8bed\u53e5\u6267\u884c\u7ed3\u675f\u540e\uff0c\u8ba1\u6570\u5668\u52a0\uff11\u3002\u5982\u679c\u8ba1\u6570\u5668\u4e3a0\uff0c\u7ebf\u7a0b\u5c06\u88ab\u963b\u585e\uff0c\u76f4\u5230\u5176\u4ed6\u7ebf\u7a0b\u7ed3\u675f\u5c06\u8ba1\u6570\u5668\u52a01\u3002\u5c3d\u7ba1\u4f60\u53ef\u4ee5\u5728\u7a0b\u5e8f\u4e2d\u50cf\u6807\u51c6\u9501\u4e00\u6837\u4f7f\u7528\u4fe1\u53f7\u91cf\u6765\u505a\u7ebf\u7a0b\u540c\u6b65\uff0c\u4f46\u662f\u8fd9\u79cd\u65b9\u5f0f\u5e76\u4e0d\u88ab\u63a8\u8350\uff0c\u56e0\u4e3a\u4f7f\u7528\u4fe1\u53f7\u91cf\u4e3a\u7a0b\u5e8f\u589e\u52a0\u7684\u590d\u6742\u6027\u4f1a\u5f71\u54cd\u7a0b\u5e8f\u6027\u80fd\u3002\u76f8\u5bf9\u4e8e\u7b80\u5355\u5730\u4f5c\u4e3a\u9501\u4f7f\u7528\uff0c\u4fe1\u53f7\u91cf\u66f4\u9002\u7528\u4e8e\u90a3\u4e9b\u9700\u8981\u5728\u7ebf\u7a0b\u4e4b\u95f4\u5f15\u5165\u4fe1\u53f7\u6216\u8005\u9650\u5236\u7684\u7a0b\u5e8f\u3002\u6bd4\u5982\uff0c\u4f60\u9700\u8981\u9650\u5236\u4e00\u6bb5\u4ee3\u7801\u7684\u5e76\u53d1\u8bbf\u95ee\u91cf\uff0c\u4f60\u5c31\u53ef\u4ee5\u50cf\u4e0b\u9762\u8fd9\u6837\u4f7f\u7528\u4fe1\u53f7\u91cf\u5b8c\u6210\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from threading import Semaphore\nimport urllib.request\n\n# At most, five threads allowed to run at once\n_fetch_url_sema = Semaphore(5)\n\ndef fetch_url(url):\n    with _fetch_url_sema:\n        return urllib.request.urlopen(url)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5982\u679c\u4f60\u5bf9\u7ebf\u7a0b\u540c\u6b65\u539f\u8bed\u7684\u5e95\u5c42\u7406\u8bba\u548c\u5b9e\u73b0\u611f\u5174\u8da3\uff0c\u53ef\u4ee5\u53c2\u8003\u64cd\u4f5c\u7cfb\u7edf\u76f8\u5173\u4e66\u7c4d\uff0c\u7edd\u5927\u591a\u6570\u90fd\u6709\u63d0\u53ca\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 12.5 \u9632\u6b62\u6b7b\u9501\u7684\u52a0\u9501\u673a\u5236\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u95ee\u9898\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4f60\u6b63\u5728\u5199\u4e00\u4e2a\u591a\u7ebf\u7a0b\u7a0b\u5e8f\uff0c\u5176\u4e2d\u7ebf\u7a0b\u9700\u8981\u4e00\u6b21\u83b7\u53d6\u591a\u4e2a\u9501\uff0c\u6b64\u65f6\u5982\u4f55\u907f\u514d\u6b7b\u9501\u95ee\u9898\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u89e3\u51b3\u65b9\u6848\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5728\u591a\u7ebf\u7a0b\u7a0b\u5e8f\u4e2d\uff0c\u6b7b\u9501\u95ee\u9898\u5f88\u5927\u4e00\u90e8\u5206\u662f\u7531\u4e8e\u7ebf\u7a0b\u540c\u65f6\u83b7\u53d6\u591a\u4e2a\u9501\u9020\u6210\u7684\u3002\u4e3e\u4e2a\u4f8b\u5b50\uff1a\u4e00\u4e2a\u7ebf\u7a0b\u83b7\u53d6\u4e86\u7b2c\u4e00\u4e2a\u9501\uff0c\u7136\u540e\u5728\u83b7\u53d6\u7b2c\u4e8c\u4e2a\u9501\u7684\n\u65f6\u5019\u53d1\u751f\u963b\u585e\uff0c\u90a3\u4e48\u8fd9\u4e2a\u7ebf\u7a0b\u5c31\u53ef\u80fd\u963b\u585e\u5176\u4ed6\u7ebf\u7a0b\u7684\u6267\u884c\uff0c\u4ece\u800c\u5bfc\u81f4\u6574\u4e2a\u7a0b\u5e8f\u5047\u6b7b\u3002\n\u89e3\u51b3\u6b7b\u9501\u95ee\u9898\u7684\u4e00\u79cd\u65b9\u6848\u662f\u4e3a\u7a0b\u5e8f\u4e2d\u7684\u6bcf\u4e00\u4e2a\u9501\u5206\u914d\u4e00\u4e2a\u552f\u4e00\u7684id\uff0c\u7136\u540e\u53ea\u5141\u8bb8\u6309\u7167\u5347\u5e8f\u89c4\u5219\u6765\u4f7f\u7528\u591a\u4e2a\u9501\uff0c\u8fd9\u4e2a\u89c4\u5219\u4f7f\u7528\u4e0a\u4e0b\u6587\u7ba1\u7406\u5668\n\u662f\u975e\u5e38\u5bb9\u6613\u5b9e\u73b0\u7684\uff0c\u793a\u4f8b\u5982\u4e0b\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "import threading\nfrom contextlib import contextmanager\n\n# Thread-local state to stored information on locks already acquired\n_local = threading.local()\n\n@contextmanager\ndef acquire(*locks):\n    # Sort locks by object identifier\n    locks = sorted(locks, key=lambda x: id(x))\n\n    # Make sure lock order of previously acquired locks is not violated\n    acquired = getattr(_local,'acquired',[])\n    if acquired and max(id(lock) for lock in acquired) >= id(locks[0]):\n        raise RuntimeError('Lock Order Violation')\n\n    # Acquire all of the locks\n    acquired.extend(locks)\n    _local.acquired = acquired\n\n    try:\n        for lock in locks:\n            lock.acquire()\n        yield\n    finally:\n        # Release locks in reverse order of acquisition\n        for lock in reversed(locks):\n            lock.release()\n        del acquired[-len(locks):]"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5982\u4f55\u4f7f\u7528\u8fd9\u4e2a\u4e0a\u4e0b\u6587\u7ba1\u7406\u5668\u5462\uff1f\u4f60\u53ef\u4ee5\u6309\u7167\u6b63\u5e38\u9014\u5f84\u521b\u5efa\u4e00\u4e2a\u9501\u5bf9\u8c61\uff0c\u4f46\u4e0d\u8bba\u662f\u5355\u4e2a\u9501\u8fd8\u662f\u591a\u4e2a\u9501\u4e2d\u90fd\u4f7f\u7528 acquire() \u51fd\u6570\u6765\u7533\u8bf7\u9501\uff0c\n\u793a\u4f8b\u5982\u4e0b\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "import threading\nx_lock = threading.Lock()\ny_lock = threading.Lock()\n\ndef thread_1():\n    while True:\n        with acquire(x_lock, y_lock):\n            print('Thread-1')\n\ndef thread_2():\n    while True:\n        with acquire(y_lock, x_lock):\n            print('Thread-2')\n\nt1 = threading.Thread(target=thread_1)\nt1.daemon = True\nt1.start()\n\nt2 = threading.Thread(target=thread_2)\nt2.daemon = True\nt2.start()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5982\u679c\u4f60\u6267\u884c\u8fd9\u6bb5\u4ee3\u7801\uff0c\u4f60\u4f1a\u53d1\u73b0\u5b83\u5373\u4f7f\u5728\u4e0d\u540c\u7684\u51fd\u6570\u4e2d\u4ee5\u4e0d\u540c\u7684\u987a\u5e8f\u83b7\u53d6\u9501\u4e5f\u6ca1\u6709\u53d1\u751f\u6b7b\u9501\u3002\n\u5176\u5173\u952e\u5728\u4e8e\uff0c\u5728\u7b2c\u4e00\u6bb5\u4ee3\u7801\u4e2d\uff0c\u6211\u4eec\u5bf9\u8fd9\u4e9b\u9501\u8fdb\u884c\u4e86\u6392\u5e8f\u3002\u901a\u8fc7\u6392\u5e8f\uff0c\u4f7f\u5f97\u4e0d\u7ba1\u7528\u6237\u4ee5\u4ec0\u4e48\u6837\u7684\u987a\u5e8f\u6765\u8bf7\u6c42\u9501\uff0c\u8fd9\u4e9b\u9501\u90fd\u4f1a\u6309\u7167\u56fa\u5b9a\u7684\u987a\u5e8f\u88ab\u83b7\u53d6\u3002\n\u5982\u679c\u6709\u591a\u4e2a acquire() \u64cd\u4f5c\u88ab\u5d4c\u5957\u8c03\u7528\uff0c\u53ef\u4ee5\u901a\u8fc7\u7ebf\u7a0b\u672c\u5730\u5b58\u50a8\uff08TLS\uff09\u6765\u68c0\u6d4b\u6f5c\u5728\u7684\u6b7b\u9501\u95ee\u9898\u3002\n\u5047\u8bbe\u4f60\u7684\u4ee3\u7801\u662f\u8fd9\u6837\u5199\u7684\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "import threading\nx_lock = threading.Lock()\ny_lock = threading.Lock()\n\ndef thread_1():\n\n    while True:\n        with acquire(x_lock):\n            with acquire(y_lock):\n                print('Thread-1')\n\ndef thread_2():\n    while True:\n        with acquire(y_lock):\n            with acquire(x_lock):\n                print('Thread-2')\n\nt1 = threading.Thread(target=thread_1)\nt1.daemon = True\nt1.start()\n\nt2 = threading.Thread(target=thread_2)\nt2.daemon = True\nt2.start()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5982\u679c\u4f60\u8fd0\u884c\u8fd9\u4e2a\u7248\u672c\u7684\u4ee3\u7801\uff0c\u5fc5\u5b9a\u4f1a\u6709\u4e00\u4e2a\u7ebf\u7a0b\u53d1\u751f\u5d29\u6e83\uff0c\u5f02\u5e38\u4fe1\u606f\u53ef\u80fd\u50cf\u8fd9\u6837\uff1a"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u53d1\u751f\u5d29\u6e83\u7684\u539f\u56e0\u5728\u4e8e\uff0c\u6bcf\u4e2a\u7ebf\u7a0b\u90fd\u8bb0\u5f55\u7740\u81ea\u5df1\u5df2\u7ecf\u83b7\u53d6\u5230\u7684\u9501\u3002 acquire() \u51fd\u6570\u4f1a\u68c0\u67e5\u4e4b\u524d\u5df2\u7ecf\u83b7\u53d6\u7684\u9501\u5217\u8868\uff0c\n\u7531\u4e8e\u9501\u662f\u6309\u7167\u5347\u5e8f\u6392\u5217\u83b7\u53d6\u7684\uff0c\u6240\u4ee5\u51fd\u6570\u4f1a\u8ba4\u4e3a\u4e4b\u524d\u5df2\u83b7\u53d6\u7684\u9501\u7684id\u5fc5\u5b9a\u5c0f\u4e8e\u65b0\u7533\u8bf7\u5230\u7684\u9501\uff0c\u8fd9\u65f6\u5c31\u4f1a\u89e6\u53d1\u5f02\u5e38\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u8ba8\u8bba\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u6b7b\u9501\u662f\u6bcf\u4e00\u4e2a\u591a\u7ebf\u7a0b\u7a0b\u5e8f\u90fd\u4f1a\u9762\u4e34\u7684\u4e00\u4e2a\u95ee\u9898\uff08\u5c31\u50cf\u5b83\u662f\u6bcf\u4e00\u672c\u64cd\u4f5c\u7cfb\u7edf\u8bfe\u672c\u7684\u5171\u540c\u8bdd\u9898\u4e00\u6837\uff09\u3002\u6839\u636e\u7ecf\u9a8c\u6765\u8bb2\uff0c\u5c3d\u53ef\u80fd\u4fdd\u8bc1\u6bcf\u4e00\u4e2a\n\u7ebf\u7a0b\u53ea\u80fd\u540c\u65f6\u4fdd\u6301\u4e00\u4e2a\u9501\uff0c\u8fd9\u6837\u7a0b\u5e8f\u5c31\u4e0d\u4f1a\u88ab\u6b7b\u9501\u95ee\u9898\u6240\u56f0\u6270\u3002\u4e00\u65e6\u6709\u7ebf\u7a0b\u540c\u65f6\u7533\u8bf7\u591a\u4e2a\u9501\uff0c\u4e00\u5207\u5c31\u4e0d\u53ef\u9884\u6599\u4e86\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u6b7b\u9501\u7684\u68c0\u6d4b\u4e0e\u6062\u590d\u662f\u4e00\u4e2a\u51e0\u4e4e\u6ca1\u6709\u4f18\u96c5\u7684\u89e3\u51b3\u65b9\u6848\u7684\u6269\u5c55\u8bdd\u9898\u3002\u4e00\u4e2a\u6bd4\u8f83\u5e38\u7528\u7684\u6b7b\u9501\u68c0\u6d4b\u4e0e\u6062\u590d\u7684\u65b9\u6848\u662f\u5f15\u5165\u770b\u95e8\u72d7\u8ba1\u6570\u5668\u3002\u5f53\u7ebf\u7a0b\u6b63\u5e38\n\u8fd0\u884c\u7684\u65f6\u5019\u4f1a\u6bcf\u9694\u4e00\u6bb5\u65f6\u95f4\u91cd\u7f6e\u8ba1\u6570\u5668\uff0c\u5728\u6ca1\u6709\u53d1\u751f\u6b7b\u9501\u7684\u60c5\u51b5\u4e0b\uff0c\u4e00\u5207\u90fd\u6b63\u5e38\u8fdb\u884c\u3002\u4e00\u65e6\u53d1\u751f\u6b7b\u9501\uff0c\u7531\u4e8e\u65e0\u6cd5\u91cd\u7f6e\u8ba1\u6570\u5668\u5bfc\u81f4\u5b9a\u65f6\u5668\n\u8d85\u65f6\uff0c\u8fd9\u65f6\u7a0b\u5e8f\u4f1a\u901a\u8fc7\u91cd\u542f\u81ea\u8eab\u6062\u590d\u5230\u6b63\u5e38\u72b6\u6001\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u907f\u514d\u6b7b\u9501\u662f\u53e6\u5916\u4e00\u79cd\u89e3\u51b3\u6b7b\u9501\u95ee\u9898\u7684\u65b9\u5f0f\uff0c\u5728\u8fdb\u7a0b\u83b7\u53d6\u9501\u7684\u65f6\u5019\u4f1a\u4e25\u683c\u6309\u7167\u5bf9\u8c61id\u5347\u5e8f\u6392\u5217\u83b7\u53d6\uff0c\u7ecf\u8fc7\u6570\u5b66\u8bc1\u660e\uff0c\u8fd9\u6837\u4fdd\u8bc1\u7a0b\u5e8f\u4e0d\u4f1a\u8fdb\u5165\n\u6b7b\u9501\u72b6\u6001\u3002\u8bc1\u660e\u5c31\u7559\u7ed9\u8bfb\u8005\u4f5c\u4e3a\u7ec3\u4e60\u4e86\u3002\u907f\u514d\u6b7b\u9501\u7684\u4e3b\u8981\u601d\u60f3\u662f\uff0c\u5355\u7eaf\u5730\u6309\u7167\u5bf9\u8c61id\u9012\u589e\u7684\u987a\u5e8f\u52a0\u9501\u4e0d\u4f1a\u4ea7\u751f\u5faa\u73af\u4f9d\u8d56\uff0c\u800c\u5faa\u73af\u4f9d\u8d56\u662f\n\u6b7b\u9501\u7684\u4e00\u4e2a\u5fc5\u8981\u6761\u4ef6\uff0c\u4ece\u800c\u907f\u514d\u7a0b\u5e8f\u8fdb\u5165\u6b7b\u9501\u72b6\u6001\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4e0b\u9762\u4ee5\u4e00\u4e2a\u5173\u4e8e\u7ebf\u7a0b\u6b7b\u9501\u7684\u7ecf\u5178\u95ee\u9898\uff1a\u201c\u54f2\u5b66\u5bb6\u5c31\u9910\u95ee\u9898\u201d\uff0c\u4f5c\u4e3a\u672c\u8282\u6700\u540e\u4e00\u4e2a\u4f8b\u5b50\u3002\u9898\u76ee\u662f\u8fd9\u6837\u7684\uff1a\u4e94\u4f4d\u54f2\u5b66\u5bb6\u56f4\u5750\u5728\u4e00\u5f20\u684c\u5b50\u524d\uff0c\u6bcf\u4e2a\u4eba\n\u9762\u524d\u6709\u4e00\u7897\u996d\u548c\u4e00\u53ea\u7b77\u5b50\u3002\u5728\u8fd9\u91cc\u6bcf\u4e2a\u54f2\u5b66\u5bb6\u53ef\u4ee5\u770b\u505a\u662f\u4e00\u4e2a\u72ec\u7acb\u7684\u7ebf\u7a0b\uff0c\u800c\u6bcf\u53ea\u7b77\u5b50\u53ef\u4ee5\u770b\u505a\u662f\u4e00\u4e2a\u9501\u3002\u6bcf\u4e2a\u54f2\u5b66\u5bb6\u53ef\u4ee5\u5904\u5728\u9759\u5750\u3001\n\u601d\u8003\u3001\u5403\u996d\u4e09\u79cd\u72b6\u6001\u4e2d\u7684\u4e00\u4e2a\u3002\u9700\u8981\u6ce8\u610f\u7684\u662f\uff0c\u6bcf\u4e2a\u54f2\u5b66\u5bb6\u5403\u996d\u662f\u9700\u8981\u4e24\u53ea\u7b77\u5b50\u7684\uff0c\u8fd9\u6837\u95ee\u9898\u5c31\u6765\u4e86\uff1a\u5982\u679c\u6bcf\u4e2a\u54f2\u5b66\u5bb6\u90fd\u62ff\u8d77\u81ea\u5df1\u5de6\u8fb9\u7684\u7b77\u5b50\uff0c\n\u90a3\u4e48\u4ed6\u4eec\u4e94\u4e2a\u90fd\u53ea\u80fd\u62ff\u7740\u4e00\u53ea\u7b77\u5b50\u5750\u5728\u90a3\u513f\uff0c\u76f4\u5230\u997f\u6b7b\u3002\u6b64\u65f6\u4ed6\u4eec\u5c31\u8fdb\u5165\u4e86\u6b7b\u9501\u72b6\u6001\u3002\n\u4e0b\u9762\u662f\u4e00\u4e2a\u7b80\u5355\u7684\u4f7f\u7528\u6b7b\u9501\u907f\u514d\u673a\u5236\u89e3\u51b3\u201c\u54f2\u5b66\u5bb6\u5c31\u9910\u95ee\u9898\u201d\u7684\u5b9e\u73b0\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "import threading\n\n# The philosopher thread\ndef philosopher(left, right):\n    while True:\n        with acquire(left,right):\n             print(threading.currentThread(), 'eating')\n\n# The chopsticks (represented by locks)\nNSTICKS = 5\nchopsticks = [threading.Lock() for n in range(NSTICKS)]\n\n# Create all of the philosophers\nfor n in range(NSTICKS):\n    t = threading.Thread(target=philosopher,\n                         args=(chopsticks[n],chopsticks[(n+1) % NSTICKS]))\n    t.start()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u6700\u540e\uff0c\u8981\u7279\u522b\u6ce8\u610f\u5230\uff0c\u4e3a\u4e86\u907f\u514d\u6b7b\u9501\uff0c\u6240\u6709\u7684\u52a0\u9501\u64cd\u4f5c\u5fc5\u987b\u4f7f\u7528 acquire() \u51fd\u6570\u3002\u5982\u679c\u4ee3\u7801\u4e2d\u7684\u67d0\u90e8\u5206\u7ed5\u8fc7acquire\n\u51fd\u6570\u76f4\u63a5\u7533\u8bf7\u9501\uff0c\u90a3\u4e48\u6574\u4e2a\u6b7b\u9501\u907f\u514d\u673a\u5236\u5c31\u4e0d\u8d77\u4f5c\u7528\u4e86\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 12.6 \u4fdd\u5b58\u7ebf\u7a0b\u7684\u72b6\u6001\u4fe1\u606f\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u95ee\u9898\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4f60\u9700\u8981\u4fdd\u5b58\u6b63\u5728\u8fd0\u884c\u7ebf\u7a0b\u7684\u72b6\u6001\uff0c\u8fd9\u4e2a\u72b6\u6001\u5bf9\u4e8e\u5176\u4ed6\u7684\u7ebf\u7a0b\u662f\u4e0d\u53ef\u89c1\u7684\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u89e3\u51b3\u65b9\u6848\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u6709\u65f6\u5728\u591a\u7ebf\u7a0b\u7f16\u7a0b\u4e2d\uff0c\u4f60\u9700\u8981\u53ea\u4fdd\u5b58\u5f53\u524d\u8fd0\u884c\u7ebf\u7a0b\u7684\u72b6\u6001\u3002\n\u8981\u8fd9\u4e48\u505a\uff0c\u53ef\u4f7f\u7528 thread.local() \u521b\u5efa\u4e00\u4e2a\u672c\u5730\u7ebf\u7a0b\u5b58\u50a8\u5bf9\u8c61\u3002\n\u5bf9\u8fd9\u4e2a\u5bf9\u8c61\u7684\u5c5e\u6027\u7684\u4fdd\u5b58\u548c\u8bfb\u53d6\u64cd\u4f5c\u90fd\u53ea\u4f1a\u5bf9\u6267\u884c\u7ebf\u7a0b\u53ef\u89c1\uff0c\u800c\u5176\u4ed6\u7ebf\u7a0b\u5e76\u4e0d\u53ef\u89c1\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4f5c\u4e3a\u4f7f\u7528\u672c\u5730\u5b58\u50a8\u7684\u4e00\u4e2a\u6709\u8da3\u7684\u5b9e\u9645\u4f8b\u5b50\uff0c\n\u8003\u8651\u57288.3\u5c0f\u8282\u5b9a\u4e49\u8fc7\u7684 LazyConnection \u4e0a\u4e0b\u6587\u7ba1\u7406\u5668\u7c7b\u3002\n\u4e0b\u9762\u6211\u4eec\u5bf9\u5b83\u8fdb\u884c\u4e00\u4e9b\u5c0f\u7684\u4fee\u6539\u4f7f\u5f97\u5b83\u53ef\u4ee5\u9002\u7528\u4e8e\u591a\u7ebf\u7a0b\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from socket import socket, AF_INET, SOCK_STREAM\nimport threading\n\nclass LazyConnection:\n    def __init__(self, address, family=AF_INET, type=SOCK_STREAM):\n        self.address = address\n        self.family = AF_INET\n        self.type = SOCK_STREAM\n        self.local = threading.local()\n\n    def __enter__(self):\n        if hasattr(self.local, 'sock'):\n            raise RuntimeError('Already connected')\n        self.local.sock = socket(self.family, self.type)\n        self.local.sock.connect(self.address)\n        return self.local.sock\n\n    def __exit__(self, exc_ty, exc_val, tb):\n        self.local.sock.close()\n        del self.local.sock"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4ee3\u7801\u4e2d\uff0c\u81ea\u5df1\u89c2\u5bdf\u5bf9\u4e8e self.local \u5c5e\u6027\u7684\u4f7f\u7528\u3002\n\u5b83\u88ab\u521d\u59cb\u5316\u4e3a\u4e00\u4e2a threading.local() \u5b9e\u4f8b\u3002\n\u5176\u4ed6\u65b9\u6cd5\u64cd\u4f5c\u88ab\u5b58\u50a8\u4e3a self.local.sock \u7684\u5957\u63a5\u5b57\u5bf9\u8c61\u3002\n\u6709\u4e86\u8fd9\u4e9b\u5c31\u53ef\u4ee5\u5728\u591a\u7ebf\u7a0b\u4e2d\u5b89\u5168\u7684\u4f7f\u7528 LazyConnection \u5b9e\u4f8b\u4e86\u3002\u4f8b\u5982\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from functools import partial\ndef test(conn):\n    with conn as s:\n        s.send(b'GET /index.html HTTP/1.0\\r\\n')\n        s.send(b'Host: www.python.org\\r\\n')\n\n        s.send(b'\\r\\n')\n        resp = b''.join(iter(partial(s.recv, 8192), b''))\n\n    print('Got {} bytes'.format(len(resp)))\n\nif __name__ == '__main__':\n    conn = LazyConnection(('www.python.org', 80))\n\n    t1 = threading.Thread(target=test, args=(conn,))\n    t2 = threading.Thread(target=test, args=(conn,))\n    t1.start()\n    t2.start()\n    t1.join()\n    t2.join()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5b83\u4e4b\u6240\u4ee5\u884c\u5f97\u901a\u7684\u539f\u56e0\u662f\u6bcf\u4e2a\u7ebf\u7a0b\u4f1a\u521b\u5efa\u4e00\u4e2a\u81ea\u5df1\u4e13\u5c5e\u7684\u5957\u63a5\u5b57\u8fde\u63a5\uff08\u5b58\u50a8\u4e3aself.local.sock\uff09\u3002\n\u56e0\u6b64\uff0c\u5f53\u4e0d\u540c\u7684\u7ebf\u7a0b\u6267\u884c\u5957\u63a5\u5b57\u64cd\u4f5c\u65f6\uff0c\u7531\u4e8e\u64cd\u4f5c\u7684\u662f\u4e0d\u540c\u7684\u5957\u63a5\u5b57\uff0c\u56e0\u6b64\u5b83\u4eec\u4e0d\u4f1a\u76f8\u4e92\u5f71\u54cd\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u8ba8\u8bba\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5728\u5927\u90e8\u5206\u7a0b\u5e8f\u4e2d\u521b\u5efa\u548c\u64cd\u4f5c\u7ebf\u7a0b\u7279\u5b9a\u72b6\u6001\u5e76\u4e0d\u4f1a\u6709\u4ec0\u4e48\u95ee\u9898\u3002\n\u4e0d\u8fc7\uff0c\u5f53\u51fa\u4e86\u95ee\u9898\u7684\u65f6\u5019\uff0c\u901a\u5e38\u662f\u56e0\u4e3a\u67d0\u4e2a\u5bf9\u8c61\u88ab\u591a\u4e2a\u7ebf\u7a0b\u4f7f\u7528\u5230\uff0c\u7528\u6765\u64cd\u4f5c\u4e00\u4e9b\u4e13\u7528\u7684\u7cfb\u7edf\u8d44\u6e90\uff0c\n\u6bd4\u5982\u4e00\u4e2a\u5957\u63a5\u5b57\u6216\u6587\u4ef6\u3002\u4f60\u4e0d\u80fd\u8ba9\u6240\u6709\u7ebf\u7a0b\u5171\u4eab\u4e00\u4e2a\u5355\u72ec\u5bf9\u8c61\uff0c\n\u56e0\u4e3a\u591a\u4e2a\u7ebf\u7a0b\u540c\u65f6\u8bfb\u548c\u5199\u7684\u65f6\u5019\u4f1a\u4ea7\u751f\u6df7\u4e71\u3002\n\u672c\u5730\u7ebf\u7a0b\u5b58\u50a8\u901a\u8fc7\u8ba9\u8fd9\u4e9b\u8d44\u6e90\u53ea\u80fd\u5728\u88ab\u4f7f\u7528\u7684\u7ebf\u7a0b\u4e2d\u53ef\u89c1\u6765\u89e3\u51b3\u8fd9\u4e2a\u95ee\u9898\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u672c\u8282\u4e2d\uff0c\u4f7f\u7528 thread.local() \u53ef\u4ee5\u8ba9 LazyConnection \u7c7b\u652f\u6301\u4e00\u4e2a\u7ebf\u7a0b\u4e00\u4e2a\u8fde\u63a5\uff0c\n\u800c\u4e0d\u662f\u5bf9\u4e8e\u6240\u6709\u7684\u8fdb\u7a0b\u90fd\u53ea\u6709\u4e00\u4e2a\u8fde\u63a5\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5176\u539f\u7406\u662f\uff0c\u6bcf\u4e2a threading.local() \u5b9e\u4f8b\u4e3a\u6bcf\u4e2a\u7ebf\u7a0b\u7ef4\u62a4\u7740\u4e00\u4e2a\u5355\u72ec\u7684\u5b9e\u4f8b\u5b57\u5178\u3002\n\u6240\u6709\u666e\u901a\u5b9e\u4f8b\u64cd\u4f5c\u6bd4\u5982\u83b7\u53d6\u3001\u4fee\u6539\u548c\u5220\u9664\u503c\u4ec5\u4ec5\u64cd\u4f5c\u8fd9\u4e2a\u5b57\u5178\u3002\n\u6bcf\u4e2a\u7ebf\u7a0b\u4f7f\u7528\u4e00\u4e2a\u72ec\u7acb\u7684\u5b57\u5178\u5c31\u53ef\u4ee5\u4fdd\u8bc1\u6570\u636e\u7684\u9694\u79bb\u4e86\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 12.7 \u521b\u5efa\u4e00\u4e2a\u7ebf\u7a0b\u6c60\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u95ee\u9898\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4f60\u521b\u5efa\u4e00\u4e2a\u5de5\u4f5c\u8005\u7ebf\u7a0b\u6c60\uff0c\u7528\u6765\u54cd\u5e94\u5ba2\u6237\u7aef\u8bf7\u6c42\u6216\u6267\u884c\u5176\u4ed6\u7684\u5de5\u4f5c\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u89e3\u51b3\u65b9\u6848\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "concurrent.futures \u51fd\u6570\u5e93\u6709\u4e00\u4e2a ThreadPoolExecutor \u7c7b\u53ef\u4ee5\u88ab\u7528\u6765\u5b8c\u6210\u8fd9\u4e2a\u4efb\u52a1\u3002\n\u4e0b\u9762\u662f\u4e00\u4e2a\u7b80\u5355\u7684TCP\u670d\u52a1\u5668\uff0c\u4f7f\u7528\u4e86\u4e00\u4e2a\u7ebf\u7a0b\u6c60\u6765\u54cd\u5e94\u5ba2\u6237\u7aef\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from socket import AF_INET, SOCK_STREAM, socket\nfrom concurrent.futures import ThreadPoolExecutor\n\ndef echo_client(sock, client_addr):\n    '''\n    Handle a client connection\n    '''\n    print('Got connection from', client_addr)\n    while True:\n        msg = sock.recv(65536)\n        if not msg:\n            break\n        sock.sendall(msg)\n    print('Client closed connection')\n    sock.close()\n\ndef echo_server(addr):\n    pool = ThreadPoolExecutor(128)\n    sock = socket(AF_INET, SOCK_STREAM)\n    sock.bind(addr)\n    sock.listen(5)\n    while True:\n        client_sock, client_addr = sock.accept()\n        pool.submit(echo_client, client_sock, client_addr)\n\necho_server(('',15000))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5982\u679c\u4f60\u60f3\u624b\u52a8\u521b\u5efa\u4f60\u81ea\u5df1\u7684\u7ebf\u7a0b\u6c60\uff0c\n\u901a\u5e38\u53ef\u4ee5\u4f7f\u7528\u4e00\u4e2aQueue\u6765\u8f7b\u677e\u5b9e\u73b0\u3002\u4e0b\u9762\u662f\u4e00\u4e2a\u7a0d\u5fae\u4e0d\u540c\u4f46\u662f\u624b\u52a8\u5b9e\u73b0\u7684\u4f8b\u5b50\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from socket import socket, AF_INET, SOCK_STREAM\nfrom threading import Thread\nfrom queue import Queue\n\ndef echo_client(q):\n    '''\n    Handle a client connection\n    '''\n    sock, client_addr = q.get()\n    print('Got connection from', client_addr)\n    while True:\n        msg = sock.recv(65536)\n        if not msg:\n            break\n        sock.sendall(msg)\n    print('Client closed connection')\n\n    sock.close()\n\ndef echo_server(addr, nworkers):\n    # Launch the client workers\n    q = Queue()\n    for n in range(nworkers):\n        t = Thread(target=echo_client, args=(q,))\n        t.daemon = True\n        t.start()\n\n    # Run the server\n    sock = socket(AF_INET, SOCK_STREAM)\n    sock.bind(addr)\n    sock.listen(5)\n    while True:\n        client_sock, client_addr = sock.accept()\n        q.put((client_sock, client_addr))\n\necho_server(('',15000), 128)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4f7f\u7528 ThreadPoolExecutor \u76f8\u5bf9\u4e8e\u624b\u52a8\u5b9e\u73b0\u7684\u4e00\u4e2a\u597d\u5904\u5728\u4e8e\u5b83\u4f7f\u5f97\n\u4efb\u52a1\u63d0\u4ea4\u8005\u66f4\u65b9\u4fbf\u7684\u4ece\u88ab\u8c03\u7528\u51fd\u6570\u4e2d\u83b7\u53d6\u8fd4\u56de\u503c\u3002\u4f8b\u5982\uff0c\u4f60\u53ef\u80fd\u4f1a\u50cf\u4e0b\u9762\u8fd9\u6837\u5199\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from concurrent.futures import ThreadPoolExecutor\nimport urllib.request\n\ndef fetch_url(url):\n    u = urllib.request.urlopen(url)\n    data = u.read()\n    return data\n\npool = ThreadPoolExecutor(10)\n# Submit work to the pool\na = pool.submit(fetch_url, 'http://www.python.org')\nb = pool.submit(fetch_url, 'http://www.pypy.org')\n\n# Get the results back\nx = a.result()\ny = b.result()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4f8b\u5b50\u4e2d\u8fd4\u56de\u7684handle\u5bf9\u8c61\u4f1a\u5e2e\u4f60\u5904\u7406\u6240\u6709\u7684\u963b\u585e\u4e0e\u534f\u4f5c\uff0c\u7136\u540e\u4ece\u5de5\u4f5c\u7ebf\u7a0b\u4e2d\u8fd4\u56de\u6570\u636e\u7ed9\u4f60\u3002\n\u7279\u522b\u7684\uff0ca.result() \u64cd\u4f5c\u4f1a\u963b\u585e\u8fdb\u7a0b\u76f4\u5230\u5bf9\u5e94\u7684\u51fd\u6570\u6267\u884c\u5b8c\u6210\u5e76\u8fd4\u56de\u4e00\u4e2a\u7ed3\u679c\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u8ba8\u8bba\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u901a\u5e38\u6765\u8bb2\uff0c\u4f60\u5e94\u8be5\u907f\u514d\u7f16\u5199\u7ebf\u7a0b\u6570\u91cf\u53ef\u4ee5\u65e0\u9650\u5236\u589e\u957f\u7684\u7a0b\u5e8f\u3002\u4f8b\u5982\uff0c\u770b\u770b\u4e0b\u9762\u8fd9\u4e2a\u670d\u52a1\u5668\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from threading import Thread\nfrom socket import socket, AF_INET, SOCK_STREAM\n\ndef echo_client(sock, client_addr):\n    '''\n    Handle a client connection\n    '''\n    print('Got connection from', client_addr)\n    while True:\n        msg = sock.recv(65536)\n        if not msg:\n            break\n        sock.sendall(msg)\n    print('Client closed connection')\n    sock.close()\n\ndef echo_server(addr, nworkers):\n    # Run the server\n    sock = socket(AF_INET, SOCK_STREAM)\n    sock.bind(addr)\n    sock.listen(5)\n    while True:\n        client_sock, client_addr = sock.accept()\n        t = Thread(target=echo_client, args=(client_sock, client_addr))\n        t.daemon = True\n        t.start()\n\necho_server(('',15000))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5c3d\u7ba1\u8fd9\u4e2a\u4e5f\u53ef\u4ee5\u5de5\u4f5c\uff0c\n\u4f46\u662f\u5b83\u4e0d\u80fd\u62b5\u5fa1\u6709\u4eba\u8bd5\u56fe\u901a\u8fc7\u521b\u5efa\u5927\u91cf\u7ebf\u7a0b\u8ba9\u4f60\u670d\u52a1\u5668\u8d44\u6e90\u67af\u7aed\u800c\u5d29\u6e83\u7684\u653b\u51fb\u884c\u4e3a\u3002\n\u901a\u8fc7\u4f7f\u7528\u9884\u5148\u521d\u59cb\u5316\u7684\u7ebf\u7a0b\u6c60\uff0c\u4f60\u53ef\u4ee5\u8bbe\u7f6e\u540c\u65f6\u8fd0\u884c\u7ebf\u7a0b\u7684\u4e0a\u9650\u6570\u91cf\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4f60\u53ef\u80fd\u4f1a\u5173\u5fc3\u521b\u5efa\u5927\u91cf\u7ebf\u7a0b\u4f1a\u6709\u4ec0\u4e48\u540e\u679c\u3002\n\u73b0\u4ee3\u64cd\u4f5c\u7cfb\u7edf\u53ef\u4ee5\u5f88\u8f7b\u677e\u7684\u521b\u5efa\u51e0\u5343\u4e2a\u7ebf\u7a0b\u7684\u7ebf\u7a0b\u6c60\u3002\n\u751a\u81f3\uff0c\u540c\u65f6\u51e0\u5343\u4e2a\u7ebf\u7a0b\u7b49\u5f85\u5de5\u4f5c\u5e76\u4e0d\u4f1a\u5bf9\u5176\u4ed6\u4ee3\u7801\u4ea7\u751f\u6027\u80fd\u5f71\u54cd\u3002\n\u5f53\u7136\u4e86\uff0c\u5982\u679c\u6240\u6709\u7ebf\u7a0b\u540c\u65f6\u88ab\u5524\u9192\u5e76\u7acb\u5373\u5728CPU\u4e0a\u6267\u884c\uff0c\u90a3\u5c31\u4e0d\u540c\u4e86\u2014\u2014\u7279\u522b\u662f\u6709\u4e86\u5168\u5c40\u89e3\u91ca\u5668\u9501GIL\u3002\n\u901a\u5e38\uff0c\u4f60\u5e94\u8be5\u53ea\u5728I/O\u5904\u7406\u76f8\u5173\u4ee3\u7801\u4e2d\u4f7f\u7528\u7ebf\u7a0b\u6c60\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u521b\u5efa\u5927\u7684\u7ebf\u7a0b\u6c60\u7684\u4e00\u4e2a\u53ef\u80fd\u9700\u8981\u5173\u6ce8\u7684\u95ee\u9898\u662f\u5185\u5b58\u7684\u4f7f\u7528\u3002\n\u4f8b\u5982\uff0c\u5982\u679c\u4f60\u5728OS X\u7cfb\u7edf\u4e0a\u9762\u521b\u5efa2000\u4e2a\u7ebf\u7a0b\uff0c\u7cfb\u7edf\u663e\u793aPython\u8fdb\u7a0b\u4f7f\u7528\u4e86\u8d85\u8fc79GB\u7684\u865a\u62df\u5185\u5b58\u3002\n\u4e0d\u8fc7\uff0c\u8fd9\u4e2a\u8ba1\u7b97\u901a\u5e38\u662f\u6709\u8bef\u5dee\u7684\u3002\u5f53\u521b\u5efa\u4e00\u4e2a\u7ebf\u7a0b\u65f6\uff0c\u64cd\u4f5c\u7cfb\u7edf\u4f1a\u9884\u7559\u4e00\u4e2a\u865a\u62df\u5185\u5b58\u533a\u57df\u6765\n\u653e\u7f6e\u7ebf\u7a0b\u7684\u6267\u884c\u6808\uff08\u901a\u5e38\u662f8MB\u5927\u5c0f\uff09\u3002\u4f46\u662f\u8fd9\u4e2a\u5185\u5b58\u53ea\u6709\u4e00\u5c0f\u7247\u6bb5\u88ab\u5b9e\u9645\u6620\u5c04\u5230\u771f\u5b9e\u5185\u5b58\u4e2d\u3002\n\u56e0\u6b64\uff0cPython\u8fdb\u7a0b\u4f7f\u7528\u5230\u7684\u771f\u5b9e\u5185\u5b58\u5176\u5b9e\u5f88\u5c0f\n\uff08\u6bd4\u5982\uff0c\u5bf9\u4e8e2000\u4e2a\u7ebf\u7a0b\u6765\u8bb2\uff0c\u53ea\u4f7f\u7528\u5230\u4e8670MB\u7684\u771f\u5b9e\u5185\u5b58\uff0c\u800c\u4e0d\u662f9GB\uff09\u3002\n\u5982\u679c\u4f60\u62c5\u5fc3\u865a\u62df\u5185\u5b58\u5927\u5c0f\uff0c\u53ef\u4ee5\u4f7f\u7528 threading.stack_size() \u51fd\u6570\u6765\u964d\u4f4e\u5b83\u3002\u4f8b\u5982\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "import threading\nthreading.stack_size(65536)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5982\u679c\u4f60\u52a0\u4e0a\u8fd9\u6761\u8bed\u53e5\u5e76\u518d\u6b21\u8fd0\u884c\u524d\u9762\u7684\u521b\u5efa2000\u4e2a\u7ebf\u7a0b\u8bd5\u9a8c\uff0c\n\u4f60\u4f1a\u53d1\u73b0Python\u8fdb\u7a0b\u53ea\u4f7f\u7528\u5230\u4e86\u5927\u6982210MB\u7684\u865a\u62df\u5185\u5b58\uff0c\u800c\u771f\u5b9e\u5185\u5b58\u4f7f\u7528\u91cf\u6ca1\u6709\u53d8\u3002\n\u6ce8\u610f\u7ebf\u7a0b\u6808\u5927\u5c0f\u5fc5\u987b\u81f3\u5c11\u4e3a32768\u5b57\u8282\uff0c\u901a\u5e38\u662f\u7cfb\u7edf\u5185\u5b58\u9875\u5927\u5c0f\uff084096\u30018192\u7b49\uff09\u7684\u6574\u6570\u500d\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 12.8 \u7b80\u5355\u7684\u5e76\u884c\u7f16\u7a0b\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u95ee\u9898\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4f60\u6709\u4e2a\u7a0b\u5e8f\u8981\u6267\u884cCPU\u5bc6\u96c6\u578b\u5de5\u4f5c\uff0c\u4f60\u60f3\u8ba9\u4ed6\u5229\u7528\u591a\u6838CPU\u7684\u4f18\u52bf\u6765\u8fd0\u884c\u7684\u5feb\u4e00\u70b9\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u89e3\u51b3\u65b9\u6848\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "concurrent.futures \u5e93\u63d0\u4f9b\u4e86\u4e00\u4e2a ProcessPoolExecutor \u7c7b\uff0c\n\u53ef\u88ab\u7528\u6765\u5728\u4e00\u4e2a\u5355\u72ec\u7684Python\u89e3\u91ca\u5668\u4e2d\u6267\u884c\u8ba1\u7b97\u5bc6\u96c6\u578b\u51fd\u6570\u3002\n\u4e0d\u8fc7\uff0c\u8981\u4f7f\u7528\u5b83\uff0c\u4f60\u9996\u5148\u8981\u6709\u4e00\u4e9b\u8ba1\u7b97\u5bc6\u96c6\u578b\u7684\u4efb\u52a1\u3002\n\u6211\u4eec\u901a\u8fc7\u4e00\u4e2a\u7b80\u5355\u800c\u5b9e\u9645\u7684\u4f8b\u5b50\u6765\u6f14\u793a\u5b83\u3002\u5047\u5b9a\u4f60\u6709\u4e2aApache web\u670d\u52a1\u5668\u65e5\u5fd7\u76ee\u5f55\u7684gzip\u538b\u7f29\u5305\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "logs/\n   20120701.log.gz\n   20120702.log.gz\n   20120703.log.gz\n   20120704.log.gz\n   20120705.log.gz\n   20120706.log.gz\n   ..."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u8fdb\u4e00\u6b65\u5047\u8bbe\u6bcf\u4e2a\u65e5\u5fd7\u6587\u4ef6\u5185\u5bb9\u7c7b\u4f3c\u4e0b\u9762\u8fd9\u6837\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "124.115.6.12 - - [10/Jul/2012:00:18:50 -0500] \"GET /robots.txt ...\" 200 71\n210.212.209.67 - - [10/Jul/2012:00:18:51 -0500] \"GET /ply/ ...\" 200 11875\n210.212.209.67 - - [10/Jul/2012:00:18:51 -0500] \"GET /favicon.ico ...\" 404 369\n61.135.216.105 - - [10/Jul/2012:00:20:04 -0500] \"GET /blog/atom.xml ...\" 304 -\n..."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4e0b\u9762\u662f\u4e00\u4e2a\u811a\u672c\uff0c\u5728\u8fd9\u4e9b\u65e5\u5fd7\u6587\u4ef6\u4e2d\u67e5\u627e\u51fa\u6240\u6709\u8bbf\u95ee\u8fc7robots.txt\u6587\u4ef6\u7684\u4e3b\u673a\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# findrobots.py\n\nimport gzip\nimport io\nimport glob\n\ndef find_robots(filename):\n    '''\n    Find all of the hosts that access robots.txt in a single log file\n    '''\n    robots = set()\n    with gzip.open(filename) as f:\n        for line in io.TextIOWrapper(f,encoding='ascii'):\n            fields = line.split()\n            if fields[6] == '/robots.txt':\n                robots.add(fields[0])\n    return robots\n\ndef find_all_robots(logdir):\n    '''\n    Find all hosts across and entire sequence of files\n    '''\n    files = glob.glob(logdir+'/*.log.gz')\n    all_robots = set()\n    for robots in map(find_robots, files):\n        all_robots.update(robots)\n    return all_robots\n\nif __name__ == '__main__':\n    robots = find_all_robots('logs')\n    for ipaddr in robots:\n        print(ipaddr)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u524d\u9762\u7684\u7a0b\u5e8f\u4f7f\u7528\u4e86\u901a\u5e38\u7684map-reduce\u98ce\u683c\u6765\u7f16\u5199\u3002\n\u51fd\u6570 find_robots() \u5728\u4e00\u4e2a\u6587\u4ef6\u540d\u96c6\u5408\u4e0a\u505amap\u64cd\u4f5c\uff0c\u5e76\u5c06\u7ed3\u679c\u6c47\u603b\u4e3a\u4e00\u4e2a\u5355\u72ec\u7684\u7ed3\u679c\uff0c\n\u4e5f\u5c31\u662f find_all_robots() \u51fd\u6570\u4e2d\u7684 all_robots \u96c6\u5408\u3002\n\u73b0\u5728\uff0c\u5047\u8bbe\u4f60\u60f3\u8981\u4fee\u6539\u8fd9\u4e2a\u7a0b\u5e8f\u8ba9\u5b83\u4f7f\u7528\u591a\u6838CPU\u3002\n\u5f88\u7b80\u5355\u2014\u2014\u53ea\u9700\u8981\u5c06map()\u64cd\u4f5c\u66ff\u6362\u4e3a\u4e00\u4e2a concurrent.futures \u5e93\u4e2d\u751f\u6210\u7684\u7c7b\u4f3c\u64cd\u4f5c\u5373\u53ef\u3002\n\u4e0b\u9762\u662f\u4e00\u4e2a\u7b80\u5355\u4fee\u6539\u7248\u672c\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# findrobots.py\n\nimport gzip\nimport io\nimport glob\nfrom concurrent import futures\n\ndef find_robots(filename):\n    '''\n    Find all of the hosts that access robots.txt in a single log file\n\n    '''\n    robots = set()\n    with gzip.open(filename) as f:\n        for line in io.TextIOWrapper(f,encoding='ascii'):\n            fields = line.split()\n            if fields[6] == '/robots.txt':\n                robots.add(fields[0])\n    return robots\n\ndef find_all_robots(logdir):\n    '''\n    Find all hosts across and entire sequence of files\n    '''\n    files = glob.glob(logdir+'/*.log.gz')\n    all_robots = set()\n    with futures.ProcessPoolExecutor() as pool:\n        for robots in pool.map(find_robots, files):\n            all_robots.update(robots)\n    return all_robots\n\nif __name__ == '__main__':\n    robots = find_all_robots('logs')\n    for ipaddr in robots:\n        print(ipaddr)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u901a\u8fc7\u8fd9\u4e2a\u4fee\u6539\u540e\uff0c\u8fd0\u884c\u8fd9\u4e2a\u811a\u672c\u4ea7\u751f\u540c\u6837\u7684\u7ed3\u679c\uff0c\u4f46\u662f\u5728\u56db\u6838\u673a\u5668\u4e0a\u9762\u6bd4\u4e4b\u524d\u5feb\u4e863.5\u500d\u3002\n\u5b9e\u9645\u7684\u6027\u80fd\u4f18\u5316\u6548\u679c\u6839\u636e\u4f60\u7684\u673a\u5668CPU\u6570\u91cf\u7684\u4e0d\u540c\u800c\u4e0d\u540c\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u8ba8\u8bba\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "ProcessPoolExecutor \u7684\u5178\u578b\u7528\u6cd5\u5982\u4e0b\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from concurrent.futures import ProcessPoolExecutor\n\nwith ProcessPoolExecutor() as pool:\n    ...\n    do work in parallel using pool\n    ..."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5176\u539f\u7406\u662f\uff0c\u4e00\u4e2a ProcessPoolExecutor \u521b\u5efaN\u4e2a\u72ec\u7acb\u7684Python\u89e3\u91ca\u5668\uff0c\nN\u662f\u7cfb\u7edf\u4e0a\u9762\u53ef\u7528CPU\u7684\u4e2a\u6570\u3002\u4f60\u53ef\u4ee5\u901a\u8fc7\u63d0\u4f9b\u53ef\u9009\u53c2\u6570\u7ed9 ProcessPoolExecutor(N) \u6765\u4fee\u6539\n\u5904\u7406\u5668\u6570\u91cf\u3002\u8fd9\u4e2a\u5904\u7406\u6c60\u4f1a\u4e00\u76f4\u8fd0\u884c\u5230with\u5757\u4e2d\u6700\u540e\u4e00\u4e2a\u8bed\u53e5\u6267\u884c\u5b8c\u6210\uff0c\n\u7136\u540e\u5904\u7406\u6c60\u88ab\u5173\u95ed\u3002\u4e0d\u8fc7\uff0c\u7a0b\u5e8f\u4f1a\u4e00\u76f4\u7b49\u5f85\u76f4\u5230\u6240\u6709\u63d0\u4ea4\u7684\u5de5\u4f5c\u88ab\u5904\u7406\u5b8c\u6210\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u88ab\u63d0\u4ea4\u5230\u6c60\u4e2d\u7684\u5de5\u4f5c\u5fc5\u987b\u88ab\u5b9a\u4e49\u4e3a\u4e00\u4e2a\u51fd\u6570\u3002\u6709\u4e24\u79cd\u65b9\u6cd5\u53bb\u63d0\u4ea4\u3002\n\u5982\u679c\u4f60\u60f3\u8ba9\u4e00\u4e2a\u5217\u8868\u63a8\u5bfc\u6216\u4e00\u4e2a map() \u64cd\u4f5c\u5e76\u884c\u6267\u884c\u7684\u8bdd\uff0c\u53ef\u4f7f\u7528 pool.map() :"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# A function that performs a lot of work\ndef work(x):\n    ...\n    return result\n\n# Nonparallel code\nresults = map(work, data)\n\n# Parallel implementation\nwith ProcessPoolExecutor() as pool:\n    results = pool.map(work, data)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u53e6\u5916\uff0c\u4f60\u53ef\u4ee5\u4f7f\u7528 pool.submit() \u6765\u624b\u52a8\u7684\u63d0\u4ea4\u5355\u4e2a\u4efb\u52a1\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# Some function\ndef work(x):\n    ...\n    return result\n\nwith ProcessPoolExecutor() as pool:\n    ...\n    # Example of submitting work to the pool\n    future_result = pool.submit(work, arg)\n\n    # Obtaining the result (blocks until done)\n    r = future_result.result()\n    ..."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5982\u679c\u4f60\u624b\u52a8\u63d0\u4ea4\u4e00\u4e2a\u4efb\u52a1\uff0c\u7ed3\u679c\u662f\u4e00\u4e2a Future \u5b9e\u4f8b\u3002\n\u8981\u83b7\u53d6\u6700\u7ec8\u7ed3\u679c\uff0c\u4f60\u9700\u8981\u8c03\u7528\u5b83\u7684 result() \u65b9\u6cd5\u3002\n\u5b83\u4f1a\u963b\u585e\u8fdb\u7a0b\u76f4\u5230\u7ed3\u679c\u88ab\u8fd4\u56de\u6765\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5982\u679c\u4e0d\u60f3\u963b\u585e\uff0c\u4f60\u8fd8\u53ef\u4ee5\u4f7f\u7528\u4e00\u4e2a\u56de\u8c03\u51fd\u6570\uff0c\u4f8b\u5982\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "def when_done(r):\n    print('Got:', r.result())\n\nwith ProcessPoolExecutor() as pool:\n     future_result = pool.submit(work, arg)\n     future_result.add_done_callback(when_done)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u56de\u8c03\u51fd\u6570\u63a5\u53d7\u4e00\u4e2a Future \u5b9e\u4f8b\uff0c\u88ab\u7528\u6765\u83b7\u53d6\u6700\u7ec8\u7684\u7ed3\u679c\uff08\u6bd4\u5982\u901a\u8fc7\u8c03\u7528\u5b83\u7684result()\u65b9\u6cd5\uff09\u3002\n\u5c3d\u7ba1\u5904\u7406\u6c60\u5f88\u5bb9\u6613\u4f7f\u7528\uff0c\u5728\u8bbe\u8ba1\u5927\u7a0b\u5e8f\u7684\u65f6\u5019\u8fd8\u662f\u6709\u5f88\u591a\u9700\u8981\u6ce8\u610f\u7684\u5730\u65b9\uff0c\u5982\u4e0b\u51e0\u70b9\uff1a"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4e00\u65e6\u542f\u52a8\u4f60\u4e0d\u80fd\u63a7\u5236\u5b50\u8fdb\u7a0b\u7684\u4efb\u4f55\u884c\u4e3a\uff0c\u56e0\u6b64\u6700\u597d\u4fdd\u6301\u7b80\u5355\u548c\u7eaf\u6d01\u2014\u2014\u51fd\u6570\u4e0d\u8981\u53bb\u4fee\u6539\u73af\u5883\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5b83\u4f1a\u514b\u9686Python\u89e3\u91ca\u5668\uff0c\u5305\u62ecfork\u65f6\u7684\u6240\u6709\u7a0b\u5e8f\u72b6\u6001\u3002\n\u800c\u5728Windows\u4e0a\uff0c\u514b\u9686\u89e3\u91ca\u5668\u65f6\u4e0d\u4f1a\u514b\u9686\u72b6\u6001\u3002\n\u5b9e\u9645\u7684fork\u64cd\u4f5c\u4f1a\u5728\u7b2c\u4e00\u6b21\u8c03\u7528 pool.map() \u6216 pool.submit() \u540e\u53d1\u751f\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4f60\u5e94\u8be5\u5728\u521b\u5efa\u4efb\u4f55\u7ebf\u7a0b\u4e4b\u524d\u5148\u521b\u5efa\u5e76\u6fc0\u6d3b\u8fdb\u7a0b\u6c60\uff08\u6bd4\u5982\u5728\u7a0b\u5e8f\u542f\u52a8\u7684main\u7ebf\u7a0b\u4e2d\u521b\u5efa\u8fdb\u7a0b\u6c60\uff09\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 12.9 Python\u7684\u5168\u5c40\u9501\u95ee\u9898\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u95ee\u9898\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4f60\u5df2\u7ecf\u542c\u8bf4\u8fc7\u5168\u5c40\u89e3\u91ca\u5668\u9501GIL\uff0c\u62c5\u5fc3\u5b83\u4f1a\u5f71\u54cd\u5230\u591a\u7ebf\u7a0b\u7a0b\u5e8f\u7684\u6267\u884c\u6027\u80fd\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u89e3\u51b3\u65b9\u6848\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5c3d\u7ba1Python\u5b8c\u5168\u652f\u6301\u591a\u7ebf\u7a0b\u7f16\u7a0b\uff0c\n\u4f46\u662f\u89e3\u91ca\u5668\u7684C\u8bed\u8a00\u5b9e\u73b0\u90e8\u5206\u5728\u5b8c\u5168\u5e76\u884c\u6267\u884c\u65f6\u5e76\u4e0d\u662f\u7ebf\u7a0b\u5b89\u5168\u7684\u3002\n\u5b9e\u9645\u4e0a\uff0c\u89e3\u91ca\u5668\u88ab\u4e00\u4e2a\u5168\u5c40\u89e3\u91ca\u5668\u9501\u4fdd\u62a4\u7740\uff0c\u5b83\u786e\u4fdd\u4efb\u4f55\u65f6\u5019\u90fd\u53ea\u6709\u4e00\u4e2aPython\u7ebf\u7a0b\u6267\u884c\u3002\nGIL\u6700\u5927\u7684\u95ee\u9898\u5c31\u662fPython\u7684\u591a\u7ebf\u7a0b\u7a0b\u5e8f\u5e76\u4e0d\u80fd\u5229\u7528\u591a\u6838CPU\u7684\u4f18\u52bf\n\uff08\u6bd4\u5982\u4e00\u4e2a\u4f7f\u7528\u4e86\u591a\u4e2a\u7ebf\u7a0b\u7684\u8ba1\u7b97\u5bc6\u96c6\u578b\u7a0b\u5e8f\u53ea\u4f1a\u5728\u4e00\u4e2a\u5355CPU\u4e0a\u9762\u8fd0\u884c\uff09\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5728\u8ba8\u8bba\u666e\u901a\u7684GIL\u4e4b\u524d\uff0c\u6709\u4e00\u70b9\u8981\u5f3a\u8c03\u7684\u662fGIL\u53ea\u4f1a\u5f71\u54cd\u5230\u90a3\u4e9b\u4e25\u91cd\u4f9d\u8d56CPU\u7684\u7a0b\u5e8f\uff08\u6bd4\u5982\u8ba1\u7b97\u578b\u7684\uff09\u3002\n\u5982\u679c\u4f60\u7684\u7a0b\u5e8f\u5927\u90e8\u5206\u53ea\u4f1a\u6d89\u53ca\u5230I/O\uff0c\u6bd4\u5982\u7f51\u7edc\u4ea4\u4e92\uff0c\u90a3\u4e48\u4f7f\u7528\u591a\u7ebf\u7a0b\u5c31\u5f88\u5408\u9002\uff0c\n\u56e0\u4e3a\u5b83\u4eec\u5927\u90e8\u5206\u65f6\u95f4\u90fd\u5728\u7b49\u5f85\u3002\u5b9e\u9645\u4e0a\uff0c\u4f60\u5b8c\u5168\u53ef\u4ee5\u653e\u5fc3\u7684\u521b\u5efa\u51e0\u5343\u4e2aPython\u7ebf\u7a0b\uff0c\n\u73b0\u4ee3\u64cd\u4f5c\u7cfb\u7edf\u8fd0\u884c\u8fd9\u4e48\u591a\u7ebf\u7a0b\u6ca1\u6709\u4efb\u4f55\u538b\u529b\uff0c\u6ca1\u5565\u53ef\u62c5\u5fc3\u7684\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u800c\u5bf9\u4e8e\u4f9d\u8d56CPU\u7684\u7a0b\u5e8f\uff0c\u4f60\u9700\u8981\u5f04\u6e05\u695a\u6267\u884c\u7684\u8ba1\u7b97\u7684\u7279\u70b9\u3002\n\u4f8b\u5982\uff0c\u4f18\u5316\u5e95\u5c42\u7b97\u6cd5\u8981\u6bd4\u4f7f\u7528\u591a\u7ebf\u7a0b\u8fd0\u884c\u5feb\u5f97\u591a\u3002\n\u7c7b\u4f3c\u7684\uff0c\u7531\u4e8ePython\u662f\u89e3\u91ca\u6267\u884c\u7684\uff0c\u5982\u679c\u4f60\u5c06\u90a3\u4e9b\u6027\u80fd\u74f6\u9888\u4ee3\u7801\u79fb\u5230\u4e00\u4e2aC\u8bed\u8a00\u6269\u5c55\u6a21\u5757\u4e2d\uff0c\n\u901f\u5ea6\u4e5f\u4f1a\u63d0\u5347\u7684\u5f88\u5feb\u3002\u5982\u679c\u4f60\u8981\u64cd\u4f5c\u6570\u7ec4\uff0c\u90a3\u4e48\u4f7f\u7528NumPy\u8fd9\u6837\u7684\u6269\u5c55\u4f1a\u975e\u5e38\u7684\u9ad8\u6548\u3002\n\u6700\u540e\uff0c\u4f60\u8fd8\u53ef\u4ee5\u8003\u8651\u4e0b\u5176\u4ed6\u53ef\u9009\u5b9e\u73b0\u65b9\u6848\uff0c\u6bd4\u5982PyPy\uff0c\u5b83\u901a\u8fc7\u4e00\u4e2aJIT\u7f16\u8bd1\u5668\u6765\u4f18\u5316\u6267\u884c\u6548\u7387\n\uff08\u4e0d\u8fc7\u5728\u5199\u8fd9\u672c\u4e66\u7684\u65f6\u5019\u5b83\u8fd8\u4e0d\u80fd\u652f\u6301Python 3\uff09\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u8fd8\u6709\u4e00\u70b9\u8981\u6ce8\u610f\u7684\u662f\uff0c\u7ebf\u7a0b\u4e0d\u662f\u4e13\u95e8\u7528\u6765\u4f18\u5316\u6027\u80fd\u7684\u3002\n\u4e00\u4e2aCPU\u4f9d\u8d56\u578b\u7a0b\u5e8f\u53ef\u80fd\u4f1a\u4f7f\u7528\u7ebf\u7a0b\u6765\u7ba1\u7406\u4e00\u4e2a\u56fe\u5f62\u7528\u6237\u754c\u9762\u3001\u4e00\u4e2a\u7f51\u7edc\u8fde\u63a5\u6216\u5176\u4ed6\u670d\u52a1\u3002\n\u8fd9\u65f6\u5019\uff0cGIL\u4f1a\u4ea7\u751f\u4e00\u4e9b\u95ee\u9898\uff0c\u56e0\u4e3a\u5982\u679c\u4e00\u4e2a\u7ebf\u7a0b\u957f\u671f\u6301\u6709GIL\u7684\u8bdd\u4f1a\u5bfc\u81f4\u5176\u4ed6\u975eCPU\u578b\u7ebf\u7a0b\u4e00\u76f4\u7b49\u5f85\u3002\n\u4e8b\u5b9e\u4e0a\uff0c\u4e00\u4e2a\u5199\u7684\u4e0d\u597d\u7684C\u8bed\u8a00\u6269\u5c55\u4f1a\u5bfc\u81f4\u8fd9\u4e2a\u95ee\u9898\u66f4\u52a0\u4e25\u91cd\uff0c\n\u5c3d\u7ba1\u4ee3\u7801\u7684\u8ba1\u7b97\u90e8\u5206\u4f1a\u6bd4\u4e4b\u524d\u8fd0\u884c\u7684\u66f4\u5feb\u4e9b\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u8bf4\u4e86\u8fd9\u4e48\u591a\uff0c\u73b0\u5728\u60f3\u8bf4\u7684\u662f\u6211\u4eec\u6709\u4e24\u79cd\u7b56\u7565\u6765\u89e3\u51b3GIL\u7684\u7f3a\u70b9\u3002\n\u9996\u5148\uff0c\u5982\u679c\u4f60\u5b8c\u5168\u5de5\u4f5c\u4e8ePython\u73af\u5883\u4e2d\uff0c\u4f60\u53ef\u4ee5\u4f7f\u7528 multiprocessing \u6a21\u5757\u6765\u521b\u5efa\u4e00\u4e2a\u8fdb\u7a0b\u6c60\uff0c\n\u5e76\u50cf\u534f\u540c\u5904\u7406\u5668\u4e00\u6837\u7684\u4f7f\u7528\u5b83\u3002\u4f8b\u5982\uff0c\u5047\u5982\u4f60\u6709\u5982\u4e0b\u7684\u7ebf\u7a0b\u4ee3\u7801\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# Performs a large calculation (CPU bound)\ndef some_work(args):\n    ...\n    return result\n\n# A thread that calls the above function\ndef some_thread():\n    while True:\n        ...\n        r = some_work(args)\n    ..."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4fee\u6539\u4ee3\u7801\uff0c\u4f7f\u7528\u8fdb\u7a0b\u6c60\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# Processing pool (see below for initiazation)\npool = None\n\n# Performs a large calculation (CPU bound)\ndef some_work(args):\n    ...\n    return result\n\n# A thread that calls the above function\ndef some_thread():\n    while True:\n        ...\n        r = pool.apply(some_work, (args))\n        ...\n\n# Initiaze the pool\nif __name__ == '__main__':\n    import multiprocessing\n    pool = multiprocessing.Pool()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u8fd9\u4e2a\u901a\u8fc7\u4f7f\u7528\u4e00\u4e2a\u6280\u5de7\u5229\u7528\u8fdb\u7a0b\u6c60\u89e3\u51b3\u4e86GIL\u7684\u95ee\u9898\u3002\n\u5f53\u4e00\u4e2a\u7ebf\u7a0b\u60f3\u8981\u6267\u884cCPU\u5bc6\u96c6\u578b\u5de5\u4f5c\u65f6\uff0c\u4f1a\u5c06\u4efb\u52a1\u53d1\u7ed9\u8fdb\u7a0b\u6c60\u3002\n\u7136\u540e\u8fdb\u7a0b\u6c60\u4f1a\u5728\u53e6\u5916\u4e00\u4e2a\u8fdb\u7a0b\u4e2d\u542f\u52a8\u4e00\u4e2a\u5355\u72ec\u7684Python\u89e3\u91ca\u5668\u6765\u5de5\u4f5c\u3002\n\u5f53\u7ebf\u7a0b\u7b49\u5f85\u7ed3\u679c\u7684\u65f6\u5019\u4f1a\u91ca\u653eGIL\u3002\n\u5e76\u4e14\uff0c\u7531\u4e8e\u8ba1\u7b97\u4efb\u52a1\u5728\u5355\u72ec\u89e3\u91ca\u5668\u4e2d\u6267\u884c\uff0c\u90a3\u4e48\u5c31\u4e0d\u4f1a\u53d7\u9650\u4e8eGIL\u4e86\u3002\n\u5728\u4e00\u4e2a\u591a\u6838\u7cfb\u7edf\u4e0a\u9762\uff0c\u4f60\u4f1a\u53d1\u73b0\u8fd9\u4e2a\u6280\u672f\u53ef\u4ee5\u8ba9\u4f60\u5f88\u597d\u7684\u5229\u7528\u591aCPU\u7684\u4f18\u52bf\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u53e6\u5916\u4e00\u4e2a\u89e3\u51b3GIL\u7684\u7b56\u7565\u662f\u4f7f\u7528C\u6269\u5c55\u7f16\u7a0b\u6280\u672f\u3002\n\u4e3b\u8981\u601d\u60f3\u662f\u5c06\u8ba1\u7b97\u5bc6\u96c6\u578b\u4efb\u52a1\u8f6c\u79fb\u7ed9C\uff0c\u8ddfPython\u72ec\u7acb\uff0c\u5728\u5de5\u4f5c\u7684\u65f6\u5019\u5728C\u4ee3\u7801\u4e2d\u91ca\u653eGIL\u3002\n\u8fd9\u53ef\u4ee5\u901a\u8fc7\u5728C\u4ee3\u7801\u4e2d\u63d2\u5165\u4e0b\u9762\u8fd9\u6837\u7684\u7279\u6b8a\u5b8f\u6765\u5b8c\u6210\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "#include \"Python.h\"\n...\n\nPyObject *pyfunc(PyObject *self, PyObject *args) {\n   ...\n   Py_BEGIN_ALLOW_THREADS\n   // Threaded C code\n   ...\n   Py_END_ALLOW_THREADS\n   ...\n}"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5982\u679c\u4f60\u4f7f\u7528\u5176\u4ed6\u5de5\u5177\u8bbf\u95eeC\u8bed\u8a00\uff0c\u6bd4\u5982\u5bf9\u4e8eCython\u7684ctypes\u5e93\uff0c\u4f60\u4e0d\u9700\u8981\u505a\u4efb\u4f55\u4e8b\u3002\n\u4f8b\u5982\uff0cctypes\u5728\u8c03\u7528C\u65f6\u4f1a\u81ea\u52a8\u91ca\u653eGIL\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u8ba8\u8bba\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u8bb8\u591a\u7a0b\u5e8f\u5458\u5728\u9762\u5bf9\u7ebf\u7a0b\u6027\u80fd\u95ee\u9898\u7684\u65f6\u5019\uff0c\u9a6c\u4e0a\u5c31\u4f1a\u602a\u7f6aGIL\uff0c\u4ec0\u4e48\u90fd\u662f\u5b83\u7684\u95ee\u9898\u3002\n\u5176\u5b9e\u8fd9\u6837\u5b50\u592a\u4e0d\u539a\u9053\u4e5f\u592a\u5929\u771f\u4e86\u70b9\u3002\n\u4f5c\u4e3a\u4e00\u4e2a\u771f\u5b9e\u7684\u4f8b\u5b50\uff0c\u5728\u591a\u7ebf\u7a0b\u7684\u7f51\u7edc\u7f16\u7a0b\u4e2d\u795e\u79d8\u7684 stalls\n\u53ef\u80fd\u662f\u56e0\u4e3a\u5176\u4ed6\u539f\u56e0\u6bd4\u5982\u4e00\u4e2aDNS\u67e5\u627e\u5ef6\u65f6\uff0c\u800c\u8ddfGIL\u6beb\u65e0\u5173\u7cfb\u3002\n\u6700\u540e\u4f60\u771f\u7684\u9700\u8981\u5148\u53bb\u641e\u61c2\u4f60\u7684\u4ee3\u7801\u662f\u5426\u771f\u7684\u88abGIL\u5f71\u54cd\u5230\u3002\n\u540c\u65f6\u8fd8\u8981\u660e\u767dGIL\u5927\u90e8\u5206\u90fd\u5e94\u8be5\u53ea\u5173\u6ce8CPU\u7684\u5904\u7406\u800c\u4e0d\u662fI/O."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5982\u679c\u4f60\u51c6\u5907\u4f7f\u7528\u4e00\u4e2a\u5904\u7406\u5668\u6c60\uff0c\u6ce8\u610f\u7684\u662f\u8fd9\u6837\u505a\u6d89\u53ca\u5230\u6570\u636e\u5e8f\u5217\u5316\u548c\u5728\u4e0d\u540cPython\u89e3\u91ca\u5668\u901a\u4fe1\u3002\n\u88ab\u6267\u884c\u7684\u64cd\u4f5c\u9700\u8981\u653e\u5728\u4e00\u4e2a\u901a\u8fc7def\u8bed\u53e5\u5b9a\u4e49\u7684Python\u51fd\u6570\u4e2d\uff0c\u4e0d\u80fd\u662flambda\u3001\u95ed\u5305\u53ef\u8c03\u7528\u5b9e\u4f8b\u7b49\uff0c\n\u5e76\u4e14\u51fd\u6570\u53c2\u6570\u548c\u8fd4\u56de\u503c\u5fc5\u987b\u8981\u517c\u5bb9pickle\u3002\n\u540c\u6837\uff0c\u8981\u6267\u884c\u7684\u4efb\u52a1\u91cf\u5fc5\u987b\u8db3\u591f\u5927\u4ee5\u5f25\u8865\u989d\u5916\u7684\u901a\u4fe1\u5f00\u9500\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u53e6\u5916\u4e00\u4e2a\u96be\u70b9\u662f\u5f53\u6df7\u5408\u4f7f\u7528\u7ebf\u7a0b\u548c\u8fdb\u7a0b\u6c60\u7684\u65f6\u5019\u4f1a\u8ba9\u4f60\u5f88\u5934\u75bc\u3002\n\u5982\u679c\u4f60\u8981\u540c\u65f6\u4f7f\u7528\u4e24\u8005\uff0c\u6700\u597d\u5728\u7a0b\u5e8f\u542f\u52a8\u65f6\uff0c\u521b\u5efa\u4efb\u4f55\u7ebf\u7a0b\u4e4b\u524d\u5148\u521b\u5efa\u4e00\u4e2a\u5355\u4f8b\u7684\u8fdb\u7a0b\u6c60\u3002\n\u7136\u540e\u7ebf\u7a0b\u4f7f\u7528\u540c\u6837\u7684\u8fdb\u7a0b\u6c60\u6765\u8fdb\u884c\u5b83\u4eec\u7684\u8ba1\u7b97\u5bc6\u96c6\u578b\u5de5\u4f5c\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "C\u6269\u5c55\u6700\u91cd\u8981\u7684\u7279\u5f81\u662f\u5b83\u4eec\u548cPython\u89e3\u91ca\u5668\u662f\u4fdd\u6301\u72ec\u7acb\u7684\u3002\n\u4e5f\u5c31\u662f\u8bf4\uff0c\u5982\u679c\u4f60\u51c6\u5907\u5c06Python\u4e2d\u7684\u4efb\u52a1\u5206\u914d\u5230C\u4e2d\u53bb\u6267\u884c\uff0c\n\u4f60\u9700\u8981\u786e\u4fddC\u4ee3\u7801\u7684\u64cd\u4f5c\u8ddfPython\u4fdd\u6301\u72ec\u7acb\uff0c\n\u8fd9\u5c31\u610f\u5473\u7740\u4e0d\u8981\u4f7f\u7528Python\u6570\u636e\u7ed3\u6784\u4ee5\u53ca\u4e0d\u8981\u8c03\u7528Python\u7684C API\u3002\n\u53e6\u5916\u4e00\u4e2a\u5c31\u662f\u4f60\u8981\u786e\u4fddC\u6269\u5c55\u6240\u505a\u7684\u5de5\u4f5c\u662f\u8db3\u591f\u7684\uff0c\u503c\u5f97\u4f60\u8fd9\u6837\u505a\u3002\n\u4e5f\u5c31\u662f\u8bf4C\u6269\u5c55\u62c5\u8d1f\u8d77\u4e86\u5927\u91cf\u7684\u8ba1\u7b97\u4efb\u52a1\uff0c\u800c\u4e0d\u662f\u5c11\u6570\u51e0\u4e2a\u8ba1\u7b97\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u8fd9\u4e9b\u89e3\u51b3GIL\u7684\u65b9\u6848\u5e76\u4e0d\u80fd\u9002\u7528\u4e8e\u6240\u6709\u95ee\u9898\u3002\n\u4f8b\u5982\uff0c\u67d0\u4e9b\u7c7b\u578b\u7684\u5e94\u7528\u7a0b\u5e8f\u5982\u679c\u88ab\u5206\u89e3\u4e3a\u591a\u4e2a\u8fdb\u7a0b\u5904\u7406\u7684\u8bdd\u5e76\u4e0d\u80fd\u5f88\u597d\u7684\u5de5\u4f5c\uff0c\n\u4e5f\u4e0d\u80fd\u5c06\u5b83\u7684\u90e8\u5206\u4ee3\u7801\u6539\u6210C\u8bed\u8a00\u6267\u884c\u3002\n\u5bf9\u4e8e\u8fd9\u4e9b\u5e94\u7528\u7a0b\u5e8f\uff0c\u4f60\u5c31\u8981\u81ea\u5df1\u9700\u6c42\u89e3\u51b3\u65b9\u6848\u4e86\n\uff08\u6bd4\u5982\u591a\u8fdb\u7a0b\u8bbf\u95ee\u5171\u4eab\u5185\u5b58\u533a\uff0c\u591a\u89e3\u6790\u5668\u8fd0\u884c\u4e8e\u540c\u4e00\u4e2a\u8fdb\u7a0b\u7b49\uff09\u3002\n\u6216\u8005\uff0c\u4f60\u8fd8\u53ef\u4ee5\u8003\u8651\u4e0b\u5176\u4ed6\u7684\u89e3\u91ca\u5668\u5b9e\u73b0\uff0c\u6bd4\u5982PyPy\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4e86\u89e3\u66f4\u591a\u5173\u4e8e\u5728C\u6269\u5c55\u4e2d\u91ca\u653eGIL\uff0c\u8bf7\u53c2\u800315.7\u548c15.10\u5c0f\u8282\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 12.10 \u5b9a\u4e49\u4e00\u4e2aActor\u4efb\u52a1\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u95ee\u9898\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4f60\u60f3\u5b9a\u4e49\u8ddfactor\u6a21\u5f0f\u4e2d\u7c7b\u4f3c\u201cactors\u201d\u89d2\u8272\u7684\u4efb\u52a1"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u89e3\u51b3\u65b9\u6848\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "actor\u6a21\u5f0f\u662f\u4e00\u79cd\u6700\u53e4\u8001\u7684\u4e5f\u662f\u6700\u7b80\u5355\u7684\u5e76\u884c\u548c\u5206\u5e03\u5f0f\u8ba1\u7b97\u89e3\u51b3\u65b9\u6848\u3002\n\u4e8b\u5b9e\u4e0a\uff0c\u5b83\u5929\u751f\u7684\u7b80\u5355\u6027\u662f\u5b83\u5982\u6b64\u53d7\u6b22\u8fce\u7684\u91cd\u8981\u539f\u56e0\u4e4b\u4e00\u3002\n\u7b80\u5355\u6765\u8bb2\uff0c\u4e00\u4e2aactor\u5c31\u662f\u4e00\u4e2a\u5e76\u53d1\u6267\u884c\u7684\u4efb\u52a1\uff0c\u53ea\u662f\u7b80\u5355\u7684\u6267\u884c\u53d1\u9001\u7ed9\u5b83\u7684\u6d88\u606f\u4efb\u52a1\u3002\n\u54cd\u5e94\u8fd9\u4e9b\u6d88\u606f\u65f6\uff0c\u5b83\u53ef\u80fd\u8fd8\u4f1a\u7ed9\u5176\u4ed6actor\u53d1\u9001\u66f4\u8fdb\u4e00\u6b65\u7684\u6d88\u606f\u3002\nactor\u4e4b\u95f4\u7684\u901a\u4fe1\u662f\u5355\u5411\u548c\u5f02\u6b65\u7684\u3002\u56e0\u6b64\uff0c\u6d88\u606f\u53d1\u9001\u8005\u4e0d\u77e5\u9053\u6d88\u606f\u662f\u4ec0\u4e48\u65f6\u5019\u88ab\u53d1\u9001\uff0c\n\u4e5f\u4e0d\u4f1a\u63a5\u6536\u5230\u4e00\u4e2a\u6d88\u606f\u5df2\u88ab\u5904\u7406\u7684\u56de\u5e94\u6216\u901a\u77e5\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u7ed3\u5408\u4f7f\u7528\u4e00\u4e2a\u7ebf\u7a0b\u548c\u4e00\u4e2a\u961f\u5217\u53ef\u4ee5\u5f88\u5bb9\u6613\u7684\u5b9a\u4e49actor\uff0c\u4f8b\u5982\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from queue import Queue\nfrom threading import Thread, Event\n\n# Sentinel used for shutdown\nclass ActorExit(Exception):\n    pass\n\nclass Actor:\n    def __init__(self):\n        self._mailbox = Queue()\n\n    def send(self, msg):\n        '''\n        Send a message to the actor\n        '''\n        self._mailbox.put(msg)\n\n    def recv(self):\n        '''\n        Receive an incoming message\n        '''\n        msg = self._mailbox.get()\n        if msg is ActorExit:\n            raise ActorExit()\n        return msg\n\n    def close(self):\n        '''\n        Close the actor, thus shutting it down\n        '''\n        self.send(ActorExit)\n\n    def start(self):\n        '''\n        Start concurrent execution\n        '''\n        self._terminated = Event()\n        t = Thread(target=self._bootstrap)\n\n        t.daemon = True\n        t.start()\n\n    def _bootstrap(self):\n        try:\n            self.run()\n        except ActorExit:\n            pass\n        finally:\n            self._terminated.set()\n\n    def join(self):\n        self._terminated.wait()\n\n    def run(self):\n        '''\n        Run method to be implemented by the user\n        '''\n        while True:\n            msg = self.recv()\n\n# Sample ActorTask\nclass PrintActor(Actor):\n    def run(self):\n        while True:\n            msg = self.recv()\n            print('Got:', msg)\n\n# Sample use\np = PrintActor()\np.start()\np.send('Hello')\np.send('World')\np.close()\np.join()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u8fd9\u4e2a\u4f8b\u5b50\u4e2d\uff0c\u4f60\u4f7f\u7528actor\u5b9e\u4f8b\u7684 send() \u65b9\u6cd5\u53d1\u9001\u6d88\u606f\u7ed9\u5b83\u4eec\u3002\n\u5176\u673a\u5236\u662f\uff0c\u8fd9\u4e2a\u65b9\u6cd5\u4f1a\u5c06\u6d88\u606f\u653e\u5165\u4e00\u4e2a\u961f\u91cc\u4e2d\uff0c\n\u7136\u540e\u5c06\u5176\u8f6c\u4ea4\u7ed9\u5904\u7406\u88ab\u63a5\u53d7\u6d88\u606f\u7684\u4e00\u4e2a\u5185\u90e8\u7ebf\u7a0b\u3002\nclose() \u65b9\u6cd5\u901a\u8fc7\u5728\u961f\u5217\u4e2d\u653e\u5165\u4e00\u4e2a\u7279\u6b8a\u7684\u54e8\u5175\u503c\uff08ActorExit\uff09\u6765\u5173\u95ed\u8fd9\u4e2aactor\u3002\n\u7528\u6237\u53ef\u4ee5\u901a\u8fc7\u7ee7\u627fActor\u5e76\u5b9a\u4e49\u5b9e\u73b0\u81ea\u5df1\u5904\u7406\u903b\u8f91run()\u65b9\u6cd5\u6765\u5b9a\u4e49\u65b0\u7684actor\u3002\nActorExit \u5f02\u5e38\u7684\u4f7f\u7528\u5c31\u662f\u7528\u6237\u81ea\u5b9a\u4e49\u4ee3\u7801\u53ef\u4ee5\u5728\u9700\u8981\u7684\u65f6\u5019\u6765\u6355\u83b7\u7ec8\u6b62\u8bf7\u6c42\n\uff08\u5f02\u5e38\u88abget()\u65b9\u6cd5\u629b\u51fa\u5e76\u4f20\u64ad\u51fa\u53bb\uff09\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5982\u679c\u4f60\u653e\u5bbd\u5bf9\u4e8e\u540c\u6b65\u548c\u5f02\u6b65\u6d88\u606f\u53d1\u9001\u7684\u8981\u6c42\uff0c\n\u7c7bactor\u5bf9\u8c61\u8fd8\u53ef\u4ee5\u901a\u8fc7\u751f\u6210\u5668\u6765\u7b80\u5316\u5b9a\u4e49\u3002\u4f8b\u5982\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "def print_actor():\n    while True:\n\n        try:\n            msg = yield      # Get a message\n            print('Got:', msg)\n        except GeneratorExit:\n            print('Actor terminating')\n\n# Sample use\np = print_actor()\nnext(p)     # Advance to the yield (ready to receive)\np.send('Hello')\np.send('World')\np.close()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u8ba8\u8bba\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "actor\u6a21\u5f0f\u7684\u9b45\u529b\u5c31\u5728\u4e8e\u5b83\u7684\u7b80\u5355\u6027\u3002\n\u5b9e\u9645\u4e0a\uff0c\u8fd9\u91cc\u4ec5\u4ec5\u53ea\u6709\u4e00\u4e2a\u6838\u5fc3\u64cd\u4f5c send() .\n\u751a\u81f3\uff0c\u5bf9\u4e8e\u5728\u57fa\u4e8eactor\u7cfb\u7edf\u4e2d\u7684\u201c\u6d88\u606f\u201d\u7684\u6cdb\u5316\u6982\u5ff5\u53ef\u4ee5\u5df2\u591a\u79cd\u65b9\u5f0f\u88ab\u6269\u5c55\u3002\n\u4f8b\u5982\uff0c\u4f60\u53ef\u4ee5\u4ee5\u5143\u7ec4\u5f62\u5f0f\u4f20\u9012\u6807\u7b7e\u6d88\u606f\uff0c\u8ba9actor\u6267\u884c\u4e0d\u540c\u7684\u64cd\u4f5c\uff0c\u5982\u4e0b\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "class TaggedActor(Actor):\n    def run(self):\n        while True:\n             tag, *payload = self.recv()\n             getattr(self,'do_'+tag)(*payload)\n\n    # Methods correponding to different message tags\n    def do_A(self, x):\n        print('Running A', x)\n\n    def do_B(self, x, y):\n        print('Running B', x, y)\n\n# Example\na = TaggedActor()\na.start()\na.send(('A', 1))      # Invokes do_A(1)\na.send(('B', 2, 3))   # Invokes do_B(2,3)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4f5c\u4e3a\u53e6\u5916\u4e00\u4e2a\u4f8b\u5b50\uff0c\u4e0b\u9762\u7684actor\u5141\u8bb8\u5728\u4e00\u4e2a\u5de5\u4f5c\u8005\u4e2d\u8fd0\u884c\u4efb\u610f\u7684\u51fd\u6570\uff0c\n\u5e76\u4e14\u901a\u8fc7\u4e00\u4e2a\u7279\u6b8a\u7684Result\u5bf9\u8c61\u8fd4\u56de\u7ed3\u679c\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from threading import Event\nclass Result:\n    def __init__(self):\n        self._evt = Event()\n        self._result = None\n\n    def set_result(self, value):\n        self._result = value\n\n        self._evt.set()\n\n    def result(self):\n        self._evt.wait()\n        return self._result\n\nclass Worker(Actor):\n    def submit(self, func, *args, **kwargs):\n        r = Result()\n        self.send((func, args, kwargs, r))\n        return r\n\n    def run(self):\n        while True:\n            func, args, kwargs, r = self.recv()\n            r.set_result(func(*args, **kwargs))\n\n# Example use\nworker = Worker()\nworker.start()\nr = worker.submit(pow, 2, 3)\nprint(r.result())"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u6700\u540e\uff0c\u201c\u53d1\u9001\u201d\u4e00\u4e2a\u4efb\u52a1\u6d88\u606f\u7684\u6982\u5ff5\u53ef\u4ee5\u88ab\u6269\u5c55\u5230\u591a\u8fdb\u7a0b\u751a\u81f3\u662f\u5927\u578b\u5206\u5e03\u5f0f\u7cfb\u7edf\u4e2d\u53bb\u3002\n\u4f8b\u5982\uff0c\u4e00\u4e2a\u7c7bactor\u5bf9\u8c61\u7684 send() \u65b9\u6cd5\u53ef\u4ee5\u88ab\u7f16\u7a0b\u8ba9\u5b83\u80fd\u5728\u4e00\u4e2a\u5957\u63a5\u5b57\u8fde\u63a5\u4e0a\u4f20\u8f93\u6570\u636e\n\u6216\u901a\u8fc7\u67d0\u4e9b\u6d88\u606f\u4e2d\u95f4\u4ef6\uff08\u6bd4\u5982AMQP\u3001ZMQ\u7b49\uff09\u6765\u53d1\u9001\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 12.11 \u5b9e\u73b0\u6d88\u606f\u53d1\u5e03/\u8ba2\u9605\u6a21\u578b\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u95ee\u9898\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4f60\u6709\u4e00\u4e2a\u57fa\u4e8e\u7ebf\u7a0b\u901a\u4fe1\u7684\u7a0b\u5e8f\uff0c\u60f3\u8ba9\u5b83\u4eec\u5b9e\u73b0\u53d1\u5e03/\u8ba2\u9605\u6a21\u5f0f\u7684\u6d88\u606f\u901a\u4fe1\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u89e3\u51b3\u65b9\u6848\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u8981\u5b9e\u73b0\u53d1\u5e03/\u8ba2\u9605\u7684\u6d88\u606f\u901a\u4fe1\u6a21\u5f0f\uff0c\n\u4f60\u901a\u5e38\u8981\u5f15\u5165\u4e00\u4e2a\u5355\u72ec\u7684\u201c\u4ea4\u6362\u673a\u201d\u6216\u201c\u7f51\u5173\u201d\u5bf9\u8c61\u4f5c\u4e3a\u6240\u6709\u6d88\u606f\u7684\u4e2d\u4ecb\u3002\n\u4e5f\u5c31\u662f\u8bf4\uff0c\u4e0d\u76f4\u63a5\u5c06\u6d88\u606f\u4ece\u4e00\u4e2a\u4efb\u52a1\u53d1\u9001\u5230\u53e6\u4e00\u4e2a\uff0c\u800c\u662f\u5c06\u5176\u53d1\u9001\u7ed9\u4ea4\u6362\u673a\uff0c\n\u7136\u540e\u7531\u4ea4\u6362\u673a\u5c06\u5b83\u53d1\u9001\u7ed9\u4e00\u4e2a\u6216\u591a\u4e2a\u88ab\u5173\u8054\u4efb\u52a1\u3002\u4e0b\u9762\u662f\u4e00\u4e2a\u975e\u5e38\u7b80\u5355\u7684\u4ea4\u6362\u673a\u5b9e\u73b0\u4f8b\u5b50\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from collections import defaultdict\n\nclass Exchange:\n    def __init__(self):\n        self._subscribers = set()\n\n    def attach(self, task):\n        self._subscribers.add(task)\n\n    def detach(self, task):\n        self._subscribers.remove(task)\n\n    def send(self, msg):\n        for subscriber in self._subscribers:\n            subscriber.send(msg)\n\n# Dictionary of all created exchanges\n_exchanges = defaultdict(Exchange)\n\n# Return the Exchange instance associated with a given name\ndef get_exchange(name):\n    return _exchanges[name]"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4e00\u4e2a\u4ea4\u6362\u673a\u5c31\u662f\u4e00\u4e2a\u666e\u901a\u5bf9\u8c61\uff0c\u8d1f\u8d23\u7ef4\u62a4\u4e00\u4e2a\u6d3b\u8dc3\u7684\u8ba2\u9605\u8005\u96c6\u5408\uff0c\u5e76\u4e3a\u7ed1\u5b9a\u3001\u89e3\u7ed1\u548c\u53d1\u9001\u6d88\u606f\u63d0\u4f9b\u76f8\u5e94\u7684\u65b9\u6cd5\u3002\n\u6bcf\u4e2a\u4ea4\u6362\u673a\u901a\u8fc7\u4e00\u4e2a\u540d\u79f0\u5b9a\u4f4d\uff0cget_exchange() \u901a\u8fc7\u7ed9\u5b9a\u4e00\u4e2a\u540d\u79f0\u8fd4\u56de\u76f8\u5e94\u7684 Exchange \u5b9e\u4f8b\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4e0b\u9762\u662f\u4e00\u4e2a\u7b80\u5355\u4f8b\u5b50\uff0c\u6f14\u793a\u4e86\u5982\u4f55\u4f7f\u7528\u4e00\u4e2a\u4ea4\u6362\u673a\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# Example of a task.  Any object with a send() method\n\nclass Task:\n    ...\n    def send(self, msg):\n        ...\n\ntask_a = Task()\ntask_b = Task()\n\n# Example of getting an exchange\nexc = get_exchange('name')\n\n# Examples of subscribing tasks to it\nexc.attach(task_a)\nexc.attach(task_b)\n\n# Example of sending messages\nexc.send('msg1')\nexc.send('msg2')\n\n# Example of unsubscribing\nexc.detach(task_a)\nexc.detach(task_b)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5c3d\u7ba1\u5bf9\u4e8e\u8fd9\u4e2a\u95ee\u9898\u6709\u5f88\u591a\u7684\u53d8\u79cd\uff0c\u4e0d\u8fc7\u4e07\u53d8\u4e0d\u79bb\u5176\u5b97\u3002\n\u6d88\u606f\u4f1a\u88ab\u53d1\u9001\u7ed9\u4e00\u4e2a\u4ea4\u6362\u673a\uff0c\u7136\u540e\u4ea4\u6362\u673a\u4f1a\u5c06\u5b83\u4eec\u53d1\u9001\u7ed9\u88ab\u7ed1\u5b9a\u7684\u8ba2\u9605\u8005\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u8ba8\u8bba\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u901a\u8fc7\u961f\u5217\u53d1\u9001\u6d88\u606f\u7684\u4efb\u52a1\u6216\u7ebf\u7a0b\u7684\u6a21\u5f0f\u5f88\u5bb9\u6613\u88ab\u5b9e\u73b0\u5e76\u4e14\u4e5f\u975e\u5e38\u666e\u904d\u3002\n\u4e0d\u8fc7\uff0c\u4f7f\u7528\u53d1\u5e03/\u8ba2\u9605\u6a21\u5f0f\u7684\u597d\u5904\u66f4\u52a0\u660e\u663e\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u9996\u5148\uff0c\u4f7f\u7528\u4e00\u4e2a\u4ea4\u6362\u673a\u53ef\u4ee5\u7b80\u5316\u5927\u90e8\u5206\u6d89\u53ca\u5230\u7ebf\u7a0b\u901a\u4fe1\u7684\u5de5\u4f5c\u3002\n\u65e0\u9700\u53bb\u5199\u901a\u8fc7\u591a\u8fdb\u7a0b\u6a21\u5757\u6765\u64cd\u4f5c\u591a\u4e2a\u7ebf\u7a0b\uff0c\u4f60\u53ea\u9700\u8981\u4f7f\u7528\u8fd9\u4e2a\u4ea4\u6362\u673a\u6765\u8fde\u63a5\u5b83\u4eec\u3002\n\u67d0\u79cd\u7a0b\u5ea6\u4e0a\uff0c\u8fd9\u4e2a\u5c31\u8ddf\u65e5\u5fd7\u6a21\u5757\u7684\u5de5\u4f5c\u539f\u7406\u7c7b\u4f3c\u3002\n\u5b9e\u9645\u4e0a\uff0c\u5b83\u53ef\u4ee5\u8f7b\u677e\u7684\u89e3\u8026\u7a0b\u5e8f\u4e2d\u591a\u4e2a\u4efb\u52a1\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5176\u6b21\uff0c\u4ea4\u6362\u673a\u5e7f\u64ad\u6d88\u606f\u7ed9\u591a\u4e2a\u8ba2\u9605\u8005\u7684\u80fd\u529b\u5e26\u6765\u4e86\u4e00\u4e2a\u5168\u65b0\u7684\u901a\u4fe1\u6a21\u5f0f\u3002\n\u4f8b\u5982\uff0c\u4f60\u53ef\u4ee5\u4f7f\u7528\u591a\u4efb\u52a1\u7cfb\u7edf\u3001\u5e7f\u64ad\u6216\u6247\u51fa\u3002\n\u4f60\u8fd8\u53ef\u4ee5\u901a\u8fc7\u4ee5\u666e\u901a\u8ba2\u9605\u8005\u8eab\u4efd\u7ed1\u5b9a\u6765\u6784\u5efa\u8c03\u8bd5\u548c\u8bca\u65ad\u5de5\u5177\u3002\n\u4f8b\u5982\uff0c\u4e0b\u9762\u662f\u4e00\u4e2a\u7b80\u5355\u7684\u8bca\u65ad\u7c7b\uff0c\u53ef\u4ee5\u663e\u793a\u88ab\u53d1\u9001\u7684\u6d88\u606f\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "class DisplayMessages:\n    def __init__(self):\n        self.count = 0\n    def send(self, msg):\n        self.count += 1\n        print('msg[{}]: {!r}'.format(self.count, msg))\n\nexc = get_exchange('name')\nd = DisplayMessages()\nexc.attach(d)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u6700\u540e\uff0c\u8be5\u5b9e\u73b0\u7684\u4e00\u4e2a\u91cd\u8981\u7279\u70b9\u662f\u5b83\u80fd\u517c\u5bb9\u591a\u4e2a\u201ctask-like\u201d\u5bf9\u8c61\u3002\n\u4f8b\u5982\uff0c\u6d88\u606f\u63a5\u53d7\u8005\u53ef\u4ee5\u662factor\uff0812.10\u5c0f\u8282\u4ecb\u7ecd\uff09\u3001\u534f\u7a0b\u3001\u7f51\u7edc\u8fde\u63a5\u6216\u4efb\u4f55\u5b9e\u73b0\u4e86\u6b63\u786e\u7684 send() \u65b9\u6cd5\u7684\u4e1c\u897f\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5173\u4e8e\u4ea4\u6362\u673a\u7684\u4e00\u4e2a\u53ef\u80fd\u95ee\u9898\u662f\u5bf9\u4e8e\u8ba2\u9605\u8005\u7684\u6b63\u786e\u7ed1\u5b9a\u548c\u89e3\u7ed1\u3002\n\u4e3a\u4e86\u6b63\u786e\u7684\u7ba1\u7406\u8d44\u6e90\uff0c\u6bcf\u4e00\u4e2a\u7ed1\u5b9a\u7684\u8ba2\u9605\u8005\u5fc5\u987b\u6700\u7ec8\u8981\u89e3\u7ed1\u3002\n\u5728\u4ee3\u7801\u4e2d\u901a\u5e38\u4f1a\u662f\u50cf\u4e0b\u9762\u8fd9\u6837\u7684\u6a21\u5f0f\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "exc = get_exchange('name')\nexc.attach(some_task)\ntry:\n    ...\nfinally:\n    exc.detach(some_task)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u67d0\u79cd\u610f\u4e49\u4e0a\uff0c\u8fd9\u4e2a\u548c\u4f7f\u7528\u6587\u4ef6\u3001\u9501\u548c\u7c7b\u4f3c\u5bf9\u8c61\u5f88\u50cf\u3002\n\u901a\u5e38\u5f88\u5bb9\u6613\u4f1a\u5fd8\u8bb0\u6700\u540e\u7684 detach() \u6b65\u9aa4\u3002\n\u4e3a\u4e86\u7b80\u5316\u8fd9\u4e2a\uff0c\u4f60\u53ef\u4ee5\u8003\u8651\u4f7f\u7528\u4e0a\u4e0b\u6587\u7ba1\u7406\u5668\u534f\u8bae\u3002\n\u4f8b\u5982\uff0c\u5728\u4ea4\u6362\u673a\u5bf9\u8c61\u4e0a\u589e\u52a0\u4e00\u4e2a subscribe() \u65b9\u6cd5\uff0c\u5982\u4e0b\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from contextlib import contextmanager\nfrom collections import defaultdict\n\nclass Exchange:\n    def __init__(self):\n        self._subscribers = set()\n\n    def attach(self, task):\n        self._subscribers.add(task)\n\n    def detach(self, task):\n        self._subscribers.remove(task)\n\n    @contextmanager\n    def subscribe(self, *tasks):\n        for task in tasks:\n            self.attach(task)\n        try:\n            yield\n        finally:\n            for task in tasks:\n                self.detach(task)\n\n    def send(self, msg):\n        for subscriber in self._subscribers:\n            subscriber.send(msg)\n\n# Dictionary of all created exchanges\n_exchanges = defaultdict(Exchange)\n\n# Return the Exchange instance associated with a given name\ndef get_exchange(name):\n    return _exchanges[name]\n\n# Example of using the subscribe() method\nexc = get_exchange('name')\nwith exc.subscribe(task_a, task_b):\n     ...\n     exc.send('msg1')\n     exc.send('msg2')\n     ...\n\n# task_a and task_b detached here"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u6700\u540e\u8fd8\u5e94\u8be5\u6ce8\u610f\u7684\u662f\u5173\u4e8e\u4ea4\u6362\u673a\u7684\u601d\u60f3\u6709\u5f88\u591a\u79cd\u7684\u6269\u5c55\u5b9e\u73b0\u3002\n\u4f8b\u5982\uff0c\u4ea4\u6362\u673a\u53ef\u4ee5\u5b9e\u73b0\u4e00\u6574\u4e2a\u6d88\u606f\u901a\u9053\u96c6\u5408\u6216\u63d0\u4f9b\u4ea4\u6362\u673a\u540d\u79f0\u7684\u6a21\u5f0f\u5339\u914d\u89c4\u5219\u3002\n\u4ea4\u6362\u673a\u8fd8\u53ef\u4ee5\u88ab\u6269\u5c55\u5230\u5206\u5e03\u5f0f\u8ba1\u7b97\u7a0b\u5e8f\u4e2d\uff08\u6bd4\u5982\uff0c\u5c06\u6d88\u606f\u8def\u7531\u5230\u4e0d\u540c\u673a\u5668\u4e0a\u9762\u7684\u4efb\u52a1\u4e2d\u53bb\uff09\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 12.12 \u4f7f\u7528\u751f\u6210\u5668\u4ee3\u66ff\u7ebf\u7a0b\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u95ee\u9898\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4f60\u60f3\u4f7f\u7528\u751f\u6210\u5668\uff08\u534f\u7a0b\uff09\u66ff\u4ee3\u7cfb\u7edf\u7ebf\u7a0b\u6765\u5b9e\u73b0\u5e76\u53d1\u3002\u8fd9\u4e2a\u6709\u65f6\u53c8\u88ab\u79f0\u4e3a\u7528\u6237\u7ea7\u7ebf\u7a0b\u6216\u7eff\u8272\u7ebf\u7a0b\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u89e3\u51b3\u65b9\u6848\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u8981\u4f7f\u7528\u751f\u6210\u5668\u5b9e\u73b0\u81ea\u5df1\u7684\u5e76\u53d1\uff0c\u4f60\u9996\u5148\u8981\u5bf9\u751f\u6210\u5668\u51fd\u6570\u548c yield \u8bed\u53e5\u6709\u6df1\u523b\u7406\u89e3\u3002\nyield \u8bed\u53e5\u4f1a\u8ba9\u4e00\u4e2a\u751f\u6210\u5668\u6302\u8d77\u5b83\u7684\u6267\u884c\uff0c\u8fd9\u6837\u5c31\u53ef\u4ee5\u7f16\u5199\u4e00\u4e2a\u8c03\u5ea6\u5668\uff0c\n\u5c06\u751f\u6210\u5668\u5f53\u505a\u67d0\u79cd\u201c\u4efb\u52a1\u201d\u5e76\u4f7f\u7528\u4efb\u52a1\u534f\u4f5c\u5207\u6362\u6765\u66ff\u6362\u5b83\u4eec\u7684\u6267\u884c\u3002\n\u8981\u6f14\u793a\u8fd9\u79cd\u601d\u60f3\uff0c\u8003\u8651\u4e0b\u9762\u4e24\u4e2a\u4f7f\u7528\u7b80\u5355\u7684 yield \u8bed\u53e5\u7684\u751f\u6210\u5668\u51fd\u6570\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# Two simple generator functions\ndef countdown(n):\n    while n > 0:\n        print('T-minus', n)\n        yield\n        n -= 1\n    print('Blastoff!')\n\ndef countup(n):\n    x = 0\n    while x < n:\n        print('Counting up', x)\n        yield\n        x += 1"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u8fd9\u4e9b\u51fd\u6570\u5728\u5185\u90e8\u4f7f\u7528yield\u8bed\u53e5\uff0c\u4e0b\u9762\u662f\u4e00\u4e2a\u5b9e\u73b0\u4e86\u7b80\u5355\u4efb\u52a1\u8c03\u5ea6\u5668\u7684\u4ee3\u7801\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from collections import deque\n\nclass TaskScheduler:\n    def __init__(self):\n        self._task_queue = deque()\n\n    def new_task(self, task):\n        '''\n        Admit a newly started task to the scheduler\n\n        '''\n        self._task_queue.append(task)\n\n    def run(self):\n        '''\n        Run until there are no more tasks\n        '''\n        while self._task_queue:\n            task = self._task_queue.popleft()\n            try:\n                # Run until the next yield statement\n                next(task)\n                self._task_queue.append(task)\n            except StopIteration:\n                # Generator is no longer executing\n                pass\n\n# Example use\nsched = TaskScheduler()\nsched.new_task(countdown(10))\nsched.new_task(countdown(5))\nsched.new_task(countup(15))\nsched.run()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "TaskScheduler \u7c7b\u5728\u4e00\u4e2a\u5faa\u73af\u4e2d\u8fd0\u884c\u751f\u6210\u5668\u96c6\u5408\u2014\u2014\u6bcf\u4e2a\u90fd\u8fd0\u884c\u5230\u78b0\u5230yield\u8bed\u53e5\u4e3a\u6b62\u3002\n\u8fd0\u884c\u8fd9\u4e2a\u4f8b\u5b50\uff0c\u8f93\u51fa\u5982\u4e0b\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "T-minus 10\nT-minus 5\nCounting up 0\nT-minus 9\nT-minus 4\nCounting up 1\nT-minus 8\nT-minus 3\nCounting up 2\nT-minus 7\nT-minus 2\n..."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5230\u6b64\u4e3a\u6b62\uff0c\u6211\u4eec\u5b9e\u9645\u4e0a\u5df2\u7ecf\u5b9e\u73b0\u4e86\u4e00\u4e2a\u201c\u64cd\u4f5c\u7cfb\u7edf\u201d\u7684\u6700\u5c0f\u6838\u5fc3\u90e8\u5206\u3002\n\u751f\u6210\u5668\u51fd\u6570\u5c31\u662f\u8ba4\u4e3a\uff0c\u800cyield\u8bed\u53e5\u662f\u4efb\u52a1\u6302\u8d77\u7684\u4fe1\u53f7\u3002\n\u8c03\u5ea6\u5668\u5faa\u73af\u68c0\u67e5\u4efb\u52a1\u5217\u8868\u76f4\u5230\u6ca1\u6709\u4efb\u52a1\u8981\u6267\u884c\u4e3a\u6b62\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5b9e\u9645\u4e0a\uff0c\u4f60\u53ef\u80fd\u60f3\u8981\u4f7f\u7528\u751f\u6210\u5668\u6765\u5b9e\u73b0\u7b80\u5355\u7684\u5e76\u53d1\u3002\n\u90a3\u4e48\uff0c\u5728\u5b9e\u73b0actor\u6216\u7f51\u7edc\u670d\u52a1\u5668\u7684\u65f6\u5019\u4f60\u53ef\u4ee5\u4f7f\u7528\u751f\u6210\u5668\u6765\u66ff\u4ee3\u7ebf\u7a0b\u7684\u4f7f\u7528\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4e0b\u9762\u7684\u4ee3\u7801\u6f14\u793a\u4e86\u4f7f\u7528\u751f\u6210\u5668\u6765\u5b9e\u73b0\u4e00\u4e2a\u4e0d\u4f9d\u8d56\u7ebf\u7a0b\u7684actor\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from collections import deque\n\nclass ActorScheduler:\n    def __init__(self):\n        self._actors = { }          # Mapping of names to actors\n        self._msg_queue = deque()   # Message queue\n\n    def new_actor(self, name, actor):\n        '''\n        Admit a newly started actor to the scheduler and give it a name\n        '''\n        self._msg_queue.append((actor,None))\n        self._actors[name] = actor\n\n    def send(self, name, msg):\n        '''\n        Send a message to a named actor\n        '''\n        actor = self._actors.get(name)\n        if actor:\n            self._msg_queue.append((actor,msg))\n\n    def run(self):\n        '''\n        Run as long as there are pending messages.\n        '''\n        while self._msg_queue:\n            actor, msg = self._msg_queue.popleft()\n            try:\n                 actor.send(msg)\n            except StopIteration:\n                 pass\n\n# Example use\nif __name__ == '__main__':\n    def printer():\n        while True:\n            msg = yield\n            print('Got:', msg)\n\n    def counter(sched):\n        while True:\n            # Receive the current count\n            n = yield\n            if n == 0:\n                break\n            # Send to the printer task\n            sched.send('printer', n)\n            # Send the next count to the counter task (recursive)\n\n            sched.send('counter', n-1)\n\n    sched = ActorScheduler()\n    # Create the initial actors\n    sched.new_actor('printer', printer())\n    sched.new_actor('counter', counter(sched))\n\n    # Send an initial message to the counter to initiate\n    sched.send('counter', 10000)\n    sched.run()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5b8c\u5168\u5f04\u61c2\u8fd9\u6bb5\u4ee3\u7801\u9700\u8981\u66f4\u6df1\u5165\u7684\u5b66\u4e60\uff0c\u4f46\u662f\u5173\u952e\u70b9\u5728\u4e8e\u6536\u96c6\u6d88\u606f\u7684\u961f\u5217\u3002\n\u672c\u8d28\u4e0a\uff0c\u8c03\u5ea6\u5668\u5728\u6709\u9700\u8981\u53d1\u9001\u7684\u6d88\u606f\u65f6\u4f1a\u4e00\u76f4\u8fd0\u884c\u7740\u3002\n\u8ba1\u6570\u751f\u6210\u5668\u4f1a\u7ed9\u81ea\u5df1\u53d1\u9001\u6d88\u606f\u5e76\u5728\u4e00\u4e2a\u9012\u5f52\u5faa\u73af\u4e2d\u7ed3\u675f\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4e0b\u9762\u662f\u4e00\u4e2a\u66f4\u52a0\u9ad8\u7ea7\u7684\u4f8b\u5b50\uff0c\u6f14\u793a\u4e86\u4f7f\u7528\u751f\u6210\u5668\u6765\u5b9e\u73b0\u4e00\u4e2a\u5e76\u53d1\u7f51\u7edc\u5e94\u7528\u7a0b\u5e8f\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from collections import deque\nfrom select import select\n\n# This class represents a generic yield event in the scheduler\nclass YieldEvent:\n    def handle_yield(self, sched, task):\n        pass\n    def handle_resume(self, sched, task):\n        pass\n\n# Task Scheduler\nclass Scheduler:\n    def __init__(self):\n        self._numtasks = 0       # Total num of tasks\n        self._ready = deque()    # Tasks ready to run\n        self._read_waiting = {}  # Tasks waiting to read\n        self._write_waiting = {} # Tasks waiting to write\n\n    # Poll for I/O events and restart waiting tasks\n    def _iopoll(self):\n        rset,wset,eset = select(self._read_waiting,\n                                self._write_waiting,[])\n        for r in rset:\n            evt, task = self._read_waiting.pop(r)\n            evt.handle_resume(self, task)\n        for w in wset:\n            evt, task = self._write_waiting.pop(w)\n            evt.handle_resume(self, task)\n\n    def new(self,task):\n        '''\n        Add a newly started task to the scheduler\n        '''\n\n        self._ready.append((task, None))\n        self._numtasks += 1\n\n    def add_ready(self, task, msg=None):\n        '''\n        Append an already started task to the ready queue.\n        msg is what to send into the task when it resumes.\n        '''\n        self._ready.append((task, msg))\n\n    # Add a task to the reading set\n    def _read_wait(self, fileno, evt, task):\n        self._read_waiting[fileno] = (evt, task)\n\n    # Add a task to the write set\n    def _write_wait(self, fileno, evt, task):\n        self._write_waiting[fileno] = (evt, task)\n\n    def run(self):\n        '''\n        Run the task scheduler until there are no tasks\n        '''\n        while self._numtasks:\n             if not self._ready:\n                  self._iopoll()\n             task, msg = self._ready.popleft()\n             try:\n                 # Run the coroutine to the next yield\n                 r = task.send(msg)\n                 if isinstance(r, YieldEvent):\n                     r.handle_yield(self, task)\n                 else:\n                     raise RuntimeError('unrecognized yield event')\n             except StopIteration:\n                 self._numtasks -= 1\n\n# Example implementation of coroutine-based socket I/O\nclass ReadSocket(YieldEvent):\n    def __init__(self, sock, nbytes):\n        self.sock = sock\n        self.nbytes = nbytes\n    def handle_yield(self, sched, task):\n        sched._read_wait(self.sock.fileno(), self, task)\n    def handle_resume(self, sched, task):\n        data = self.sock.recv(self.nbytes)\n        sched.add_ready(task, data)\n\nclass WriteSocket(YieldEvent):\n    def __init__(self, sock, data):\n        self.sock = sock\n        self.data = data\n    def handle_yield(self, sched, task):\n\n        sched._write_wait(self.sock.fileno(), self, task)\n    def handle_resume(self, sched, task):\n        nsent = self.sock.send(self.data)\n        sched.add_ready(task, nsent)\n\nclass AcceptSocket(YieldEvent):\n    def __init__(self, sock):\n        self.sock = sock\n    def handle_yield(self, sched, task):\n        sched._read_wait(self.sock.fileno(), self, task)\n    def handle_resume(self, sched, task):\n        r = self.sock.accept()\n        sched.add_ready(task, r)\n\n# Wrapper around a socket object for use with yield\nclass Socket(object):\n    def __init__(self, sock):\n        self._sock = sock\n    def recv(self, maxbytes):\n        return ReadSocket(self._sock, maxbytes)\n    def send(self, data):\n        return WriteSocket(self._sock, data)\n    def accept(self):\n        return AcceptSocket(self._sock)\n    def __getattr__(self, name):\n        return getattr(self._sock, name)\n\nif __name__ == '__main__':\n    from socket import socket, AF_INET, SOCK_STREAM\n    import time\n\n    # Example of a function involving generators.  This should\n    # be called using line = yield from readline(sock)\n    def readline(sock):\n        chars = []\n        while True:\n            c = yield sock.recv(1)\n            if not c:\n                break\n            chars.append(c)\n            if c == b'\\n':\n                break\n        return b''.join(chars)\n\n    # Echo server using generators\n    class EchoServer:\n        def __init__(self,addr,sched):\n            self.sched = sched\n            sched.new(self.server_loop(addr))\n\n        def server_loop(self,addr):\n            s = Socket(socket(AF_INET,SOCK_STREAM))\n\n            s.bind(addr)\n            s.listen(5)\n            while True:\n                c,a = yield s.accept()\n                print('Got connection from ', a)\n                self.sched.new(self.client_handler(Socket(c)))\n\n        def client_handler(self,client):\n            while True:\n                line = yield from readline(client)\n                if not line:\n                    break\n                line = b'GOT:' + line\n                while line:\n                    nsent = yield client.send(line)\n                    line = line[nsent:]\n            client.close()\n            print('Client closed')\n\n    sched = Scheduler()\n    EchoServer(('',16000),sched)\n    sched.run()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u8fd9\u6bb5\u4ee3\u7801\u6709\u70b9\u590d\u6742\u3002\u4e0d\u8fc7\uff0c\u5b83\u5b9e\u73b0\u4e86\u4e00\u4e2a\u5c0f\u578b\u7684\u64cd\u4f5c\u7cfb\u7edf\u3002\n\u6709\u4e00\u4e2a\u5c31\u7eea\u7684\u4efb\u52a1\u961f\u5217\uff0c\u5e76\u4e14\u8fd8\u6709\u56e0I/O\u4f11\u7720\u7684\u4efb\u52a1\u7b49\u5f85\u533a\u57df\u3002\n\u8fd8\u6709\u5f88\u591a\u8c03\u5ea6\u5668\u8d1f\u8d23\u5728\u5c31\u7eea\u961f\u5217\u548cI/O\u7b49\u5f85\u533a\u57df\u4e4b\u95f4\u79fb\u52a8\u4efb\u52a1\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u8ba8\u8bba\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5728\u6784\u5efa\u57fa\u4e8e\u751f\u6210\u5668\u7684\u5e76\u53d1\u6846\u67b6\u65f6\uff0c\u901a\u5e38\u4f1a\u4f7f\u7528\u66f4\u5e38\u89c1\u7684yield\u5f62\u5f0f\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "def some_generator():\n    ...\n    result = yield data\n    ..."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4f7f\u7528\u8fd9\u79cd\u5f62\u5f0f\u7684yield\u8bed\u53e5\u7684\u51fd\u6570\u901a\u5e38\u88ab\u79f0\u4e3a\u201c\u534f\u7a0b\u201d\u3002\n\u901a\u8fc7\u8c03\u5ea6\u5668\uff0cyield\u8bed\u53e5\u5728\u4e00\u4e2a\u5faa\u73af\u4e2d\u88ab\u5904\u7406\uff0c\u5982\u4e0b\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "f = some_generator()\n\n# Initial result. Is None to start since nothing has been computed\nresult = None\nwhile True:\n    try:\n        data = f.send(result)\n        result = ... do some calculation ...\n    except StopIteration:\n        break"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u8fd9\u91cc\u7684\u903b\u8f91\u7a0d\u5fae\u6709\u70b9\u590d\u6742\u3002\u4e0d\u8fc7\uff0c\u88ab\u4f20\u7ed9 send() \u7684\u503c\u5b9a\u4e49\u4e86\u5728yield\u8bed\u53e5\u9192\u6765\u65f6\u7684\u8fd4\u56de\u503c\u3002\n\u56e0\u6b64\uff0c\u5982\u679c\u4e00\u4e2ayield\u51c6\u5907\u5728\u5bf9\u4e4b\u524dyield\u6570\u636e\u7684\u56de\u5e94\u4e2d\u8fd4\u56de\u7ed3\u679c\u65f6\uff0c\u4f1a\u5728\u4e0b\u4e00\u6b21 send() \u64cd\u4f5c\u8fd4\u56de\u3002\n\u5982\u679c\u4e00\u4e2a\u751f\u6210\u5668\u51fd\u6570\u521a\u5f00\u59cb\u8fd0\u884c\uff0c\u53d1\u9001\u4e00\u4e2aNone\u503c\u4f1a\u8ba9\u5b83\u6392\u5728\u7b2c\u4e00\u4e2ayield\u8bed\u53e5\u524d\u9762\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u9664\u4e86\u53d1\u9001\u503c\u5916\uff0c\u8fd8\u53ef\u4ee5\u5728\u4e00\u4e2a\u751f\u6210\u5668\u4e0a\u9762\u6267\u884c\u4e00\u4e2a close() \u65b9\u6cd5\u3002\n\u5b83\u4f1a\u5bfc\u81f4\u5728\u6267\u884cyield\u8bed\u53e5\u65f6\u629b\u51fa\u4e00\u4e2a GeneratorExit \u5f02\u5e38\uff0c\u4ece\u800c\u7ec8\u6b62\u6267\u884c\u3002\n\u5982\u679c\u8fdb\u4e00\u6b65\u8bbe\u8ba1\uff0c\u4e00\u4e2a\u751f\u6210\u5668\u53ef\u4ee5\u6355\u83b7\u8fd9\u4e2a\u5f02\u5e38\u5e76\u6267\u884c\u6e05\u7406\u64cd\u4f5c\u3002\n\u540c\u6837\u8fd8\u53ef\u4ee5\u4f7f\u7528\u751f\u6210\u5668\u7684 throw() \u65b9\u6cd5\u5728yield\u8bed\u53e5\u6267\u884c\u65f6\u751f\u6210\u4e00\u4e2a\u4efb\u610f\u7684\u6267\u884c\u6307\u4ee4\u3002\n\u4e00\u4e2a\u4efb\u52a1\u8c03\u5ea6\u5668\u53ef\u5229\u7528\u5b83\u6765\u5728\u8fd0\u884c\u7684\u751f\u6210\u5668\u4e2d\u5904\u7406\u9519\u8bef\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u6700\u540e\u4e00\u4e2a\u4f8b\u5b50\u4e2d\u4f7f\u7528\u7684 yield from \u8bed\u53e5\u88ab\u7528\u6765\u5b9e\u73b0\u534f\u7a0b\uff0c\u53ef\u4ee5\u88ab\u5176\u5b83\u751f\u6210\u5668\u4f5c\u4e3a\u5b50\u7a0b\u5e8f\u6216\u8fc7\u7a0b\u6765\u8c03\u7528\u3002\n\u672c\u8d28\u4e0a\u5c31\u662f\u5c06\u63a7\u5236\u6743\u900f\u660e\u7684\u4f20\u8f93\u7ed9\u65b0\u7684\u51fd\u6570\u3002\n\u4e0d\u50cf\u666e\u901a\u7684\u751f\u6210\u5668\uff0c\u4e00\u4e2a\u4f7f\u7528 yield from \u88ab\u8c03\u7528\u7684\u51fd\u6570\u53ef\u4ee5\u8fd4\u56de\u4e00\u4e2a\u4f5c\u4e3a yield from \u8bed\u53e5\u7ed3\u679c\u7684\u503c\u3002\n\u5173\u4e8e yield from \u7684\u66f4\u591a\u4fe1\u606f\u53ef\u4ee5\u5728 PEP 380 \u4e2d\u627e\u5230\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u6700\u540e\uff0c\u5982\u679c\u4f7f\u7528\u751f\u6210\u5668\u7f16\u7a0b\uff0c\u8981\u63d0\u9192\u4f60\u7684\u662f\u5b83\u8fd8\u662f\u6709\u5f88\u591a\u7f3a\u70b9\u7684\u3002\n\u7279\u522b\u662f\uff0c\u4f60\u5f97\u4e0d\u5230\u4efb\u4f55\u7ebf\u7a0b\u53ef\u4ee5\u63d0\u4f9b\u7684\u597d\u5904\u3002\u4f8b\u5982\uff0c\u5982\u679c\u4f60\u6267\u884cCPU\u4f9d\u8d56\u6216I/O\u963b\u585e\u7a0b\u5e8f\uff0c\n\u5b83\u4f1a\u5c06\u6574\u4e2a\u4efb\u52a1\u6302\u8d77\u77e5\u9053\u64cd\u4f5c\u5b8c\u6210\u3002\u4e3a\u4e86\u89e3\u51b3\u8fd9\u4e2a\u95ee\u9898\uff0c\n\u4f60\u53ea\u80fd\u9009\u62e9\u5c06\u64cd\u4f5c\u59d4\u6d3e\u7ed9\u53e6\u5916\u4e00\u4e2a\u53ef\u4ee5\u72ec\u7acb\u8fd0\u884c\u7684\u7ebf\u7a0b\u6216\u8fdb\u7a0b\u3002\n\u53e6\u5916\u4e00\u4e2a\u9650\u5236\u662f\u5927\u90e8\u5206Python\u5e93\u5e76\u4e0d\u80fd\u5f88\u597d\u7684\u517c\u5bb9\u57fa\u4e8e\u751f\u6210\u5668\u7684\u7ebf\u7a0b\u3002\n\u5982\u679c\u4f60\u9009\u62e9\u8fd9\u4e2a\u65b9\u6848\uff0c\u4f60\u4f1a\u53d1\u73b0\u4f60\u9700\u8981\u81ea\u5df1\u6539\u5199\u5f88\u591a\u6807\u51c6\u5e93\u51fd\u6570\u3002\n\u4f5c\u4e3a\u672c\u8282\u63d0\u5230\u7684\u534f\u7a0b\u548c\u76f8\u5173\u6280\u672f\u7684\u4e00\u4e2a\u57fa\u7840\u80cc\u666f\uff0c\u53ef\u4ee5\u67e5\u770b PEP 342\n\u548c \u201c\u534f\u7a0b\u548c\u5e76\u53d1\u7684\u4e00\u95e8\u6709\u8da3\u8bfe\u7a0b\u201d"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "PEP 3156 \u540c\u6837\u6709\u4e00\u4e2a\u5173\u4e8e\u4f7f\u7528\u534f\u7a0b\u7684\u5f02\u6b65I/O\u6a21\u578b\u3002\n\u7279\u522b\u7684\uff0c\u4f60\u4e0d\u53ef\u80fd\u81ea\u5df1\u53bb\u5b9e\u73b0\u4e00\u4e2a\u5e95\u5c42\u7684\u534f\u7a0b\u8c03\u5ea6\u5668\u3002\n\u4e0d\u8fc7\uff0c\u5173\u4e8e\u534f\u7a0b\u7684\u601d\u60f3\u662f\u5f88\u591a\u6d41\u884c\u5e93\u7684\u57fa\u7840\uff0c\n\u5305\u62ec gevent,\ngreenlet,\nStackless Python \u4ee5\u53ca\u5176\u4ed6\u7c7b\u4f3c\u5de5\u7a0b\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 12.13 \u591a\u4e2a\u7ebf\u7a0b\u961f\u5217\u8f6e\u8be2\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u95ee\u9898\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4f60\u6709\u4e00\u4e2a\u7ebf\u7a0b\u961f\u5217\u96c6\u5408\uff0c\u60f3\u4e3a\u5230\u6765\u7684\u5143\u7d20\u8f6e\u8be2\u5b83\u4eec\uff0c\n\u5c31\u8ddf\u4f60\u4e3a\u4e00\u4e2a\u5ba2\u6237\u7aef\u8bf7\u6c42\u53bb\u8f6e\u8be2\u4e00\u4e2a\u7f51\u7edc\u8fde\u63a5\u96c6\u5408\u7684\u65b9\u5f0f\u4e00\u6837\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u89e3\u51b3\u65b9\u6848\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5bf9\u4e8e\u8f6e\u8be2\u95ee\u9898\u7684\u4e00\u4e2a\u5e38\u89c1\u89e3\u51b3\u65b9\u6848\u4e2d\u6709\u4e2a\u5f88\u5c11\u6709\u4eba\u77e5\u9053\u7684\u6280\u5de7\uff0c\u5305\u542b\u4e86\u4e00\u4e2a\u9690\u85cf\u7684\u56de\u8def\u7f51\u7edc\u8fde\u63a5\u3002\n\u672c\u8d28\u4e0a\u8bb2\u5176\u601d\u60f3\u5c31\u662f\uff1a\u5bf9\u4e8e\u6bcf\u4e2a\u4f60\u60f3\u8981\u8f6e\u8be2\u7684\u961f\u5217\uff0c\u4f60\u521b\u5efa\u4e00\u5bf9\u8fde\u63a5\u7684\u5957\u63a5\u5b57\u3002\n\u7136\u540e\u4f60\u5728\u5176\u4e2d\u4e00\u4e2a\u5957\u63a5\u5b57\u4e0a\u9762\u7f16\u5199\u4ee3\u7801\u6765\u6807\u8bc6\u5b58\u5728\u7684\u6570\u636e\uff0c\n\u53e6\u5916\u4e00\u4e2a\u5957\u63a5\u5b57\u88ab\u4f20\u7ed9 select() \u6216\u7c7b\u4f3c\u7684\u4e00\u4e2a\u8f6e\u8be2\u6570\u636e\u5230\u8fbe\u7684\u51fd\u6570\u3002\u4e0b\u9762\u7684\u4f8b\u5b50\u6f14\u793a\u4e86\u8fd9\u4e2a\u601d\u60f3\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "import queue\nimport socket\nimport os\n\nclass PollableQueue(queue.Queue):\n    def __init__(self):\n        super().__init__()\n        # Create a pair of connected sockets\n        if os.name == 'posix':\n            self._putsocket, self._getsocket = socket.socketpair()\n        else:\n            # Compatibility on non-POSIX systems\n            server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n            server.bind(('127.0.0.1', 0))\n            server.listen(1)\n            self._putsocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n            self._putsocket.connect(server.getsockname())\n            self._getsocket, _ = server.accept()\n            server.close()\n\n    def fileno(self):\n        return self._getsocket.fileno()\n\n    def put(self, item):\n        super().put(item)\n        self._putsocket.send(b'x')\n\n    def get(self):\n        self._getsocket.recv(1)\n        return super().get()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5728\u8fd9\u4e2a\u4ee3\u7801\u4e2d\uff0c\u4e00\u4e2a\u65b0\u7684 Queue \u5b9e\u4f8b\u7c7b\u578b\u88ab\u5b9a\u4e49\uff0c\u5e95\u5c42\u662f\u4e00\u4e2a\u88ab\u8fde\u63a5\u5957\u63a5\u5b57\u5bf9\u3002\n\u5728Unix\u673a\u5668\u4e0a\u7684 socketpair() \u51fd\u6570\u80fd\u8f7b\u677e\u7684\u521b\u5efa\u8fd9\u6837\u7684\u5957\u63a5\u5b57\u3002\n\u5728Windows\u4e0a\u9762\uff0c\u4f60\u5fc5\u987b\u4f7f\u7528\u7c7b\u4f3c\u4ee3\u7801\u6765\u6a21\u62df\u5b83\u3002\n\u7136\u540e\u5b9a\u4e49\u666e\u901a\u7684 get() \u548c put() \u65b9\u6cd5\u5728\u8fd9\u4e9b\u5957\u63a5\u5b57\u4e0a\u9762\u6765\u6267\u884cI/O\u64cd\u4f5c\u3002\nput() \u65b9\u6cd5\u518d\u5c06\u6570\u636e\u653e\u5165\u961f\u5217\u540e\u4f1a\u5199\u4e00\u4e2a\u5355\u5b57\u8282\u5230\u67d0\u4e2a\u5957\u63a5\u5b57\u4e2d\u53bb\u3002\n\u800c get() \u65b9\u6cd5\u5728\u4ece\u961f\u5217\u4e2d\u79fb\u9664\u4e00\u4e2a\u5143\u7d20\u65f6\u4f1a\u4ece\u53e6\u5916\u4e00\u4e2a\u5957\u63a5\u5b57\u4e2d\u8bfb\u53d6\u5230\u8fd9\u4e2a\u5355\u5b57\u8282\u6570\u636e\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "fileno() \u65b9\u6cd5\u4f7f\u7528\u4e00\u4e2a\u51fd\u6570\u6bd4\u5982 select() \u6765\u8ba9\u8fd9\u4e2a\u961f\u5217\u53ef\u4ee5\u88ab\u8f6e\u8be2\u3002\n\u5b83\u4ec5\u4ec5\u53ea\u662f\u66b4\u9732\u4e86\u5e95\u5c42\u88ab get() \u51fd\u6570\u4f7f\u7528\u5230\u7684socket\u7684\u6587\u4ef6\u63cf\u8ff0\u7b26\u800c\u5df2\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4e0b\u9762\u662f\u4e00\u4e2a\u4f8b\u5b50\uff0c\u5b9a\u4e49\u4e86\u4e00\u4e2a\u4e3a\u5230\u6765\u7684\u5143\u7d20\u76d1\u63a7\u591a\u4e2a\u961f\u5217\u7684\u6d88\u8d39\u8005\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "import select\nimport threading\n\ndef consumer(queues):\n    '''\n    Consumer that reads data on multiple queues simultaneously\n    '''\n    while True:\n        can_read, _, _ = select.select(queues,[],[])\n        for r in can_read:\n            item = r.get()\n            print('Got:', item)\n\nq1 = PollableQueue()\nq2 = PollableQueue()\nq3 = PollableQueue()\nt = threading.Thread(target=consumer, args=([q1,q2,q3],))\nt.daemon = True\nt.start()\n\n# Feed data to the queues\nq1.put(1)\nq2.put(10)\nq3.put('hello')\nq2.put(15)\n..."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5982\u679c\u4f60\u8bd5\u7740\u8fd0\u884c\u5b83\uff0c\u4f60\u4f1a\u53d1\u73b0\u8fd9\u4e2a\u6d88\u8d39\u8005\u4f1a\u63a5\u53d7\u5230\u6240\u6709\u7684\u88ab\u653e\u5165\u7684\u5143\u7d20\uff0c\u4e0d\u7ba1\u5143\u7d20\u88ab\u653e\u8fdb\u4e86\u54ea\u4e2a\u961f\u5217\u4e2d\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u8ba8\u8bba\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5bf9\u4e8e\u8f6e\u8be2\u975e\u7c7b\u6587\u4ef6\u5bf9\u8c61\uff0c\u6bd4\u5982\u961f\u5217\u901a\u5e38\u90fd\u662f\u6bd4\u8f83\u68d8\u624b\u7684\u95ee\u9898\u3002\n\u4f8b\u5982\uff0c\u5982\u679c\u4f60\u4e0d\u4f7f\u7528\u4e0a\u9762\u7684\u5957\u63a5\u5b57\u6280\u672f\uff0c\n\u4f60\u552f\u4e00\u7684\u9009\u62e9\u5c31\u662f\u7f16\u5199\u4ee3\u7801\u6765\u5faa\u73af\u904d\u5386\u8fd9\u4e9b\u961f\u5217\u5e76\u4f7f\u7528\u4e00\u4e2a\u5b9a\u65f6\u5668\u3002\u50cf\u4e0b\u9762\u8fd9\u6837\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "import time\ndef consumer(queues):\n    while True:\n        for q in queues:\n            if not q.empty():\n                item = q.get()\n                print('Got:', item)\n\n        # Sleep briefly to avoid 100% CPU\n        time.sleep(0.01)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u8fd9\u6837\u505a\u5176\u5b9e\u4e0d\u5408\u7406\uff0c\u8fd8\u4f1a\u5f15\u5165\u5176\u4ed6\u7684\u6027\u80fd\u95ee\u9898\u3002\n\u4f8b\u5982\uff0c\u5982\u679c\u65b0\u7684\u6570\u636e\u88ab\u52a0\u5165\u5230\u4e00\u4e2a\u961f\u5217\u4e2d\uff0c\u81f3\u5c11\u8981\u82b110\u6beb\u79d2\u624d\u80fd\u88ab\u53d1\u73b0\u3002\n\u5982\u679c\u4f60\u4e4b\u524d\u7684\u8f6e\u8be2\u8fd8\u8981\u53bb\u8f6e\u8be2\u5176\u4ed6\u5bf9\u8c61\uff0c\u6bd4\u5982\u7f51\u7edc\u5957\u63a5\u5b57\u90a3\u8fd8\u4f1a\u6709\u66f4\u591a\u95ee\u9898\u3002\n\u4f8b\u5982\uff0c\u5982\u679c\u4f60\u60f3\u540c\u65f6\u8f6e\u8be2\u5957\u63a5\u5b57\u548c\u961f\u5217\uff0c\u4f60\u53ef\u80fd\u8981\u50cf\u4e0b\u9762\u8fd9\u6837\u4f7f\u7528\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "import select\n\ndef event_loop(sockets, queues):\n    while True:\n        # polling with a timeout\n        can_read, _, _ = select.select(sockets, [], [], 0.01)\n        for r in can_read:\n            handle_read(r)\n        for q in queues:\n            if not q.empty():\n                item = q.get()\n                print('Got:', item)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u8fd9\u4e2a\u65b9\u6848\u901a\u8fc7\u5c06\u961f\u5217\u548c\u5957\u63a5\u5b57\u7b49\u540c\u5bf9\u5f85\u6765\u89e3\u51b3\u4e86\u5927\u90e8\u5206\u7684\u95ee\u9898\u3002\n\u4e00\u4e2a\u5355\u72ec\u7684 select() \u8c03\u7528\u53ef\u88ab\u540c\u65f6\u7528\u6765\u8f6e\u8be2\u3002\n\u4f7f\u7528\u8d85\u65f6\u6216\u5176\u4ed6\u57fa\u4e8e\u65f6\u95f4\u7684\u673a\u5236\u6765\u6267\u884c\u5468\u671f\u6027\u68c0\u67e5\u5e76\u6ca1\u6709\u5fc5\u8981\u3002\n\u751a\u81f3\uff0c\u5982\u679c\u6570\u636e\u88ab\u52a0\u5165\u5230\u4e00\u4e2a\u961f\u5217\uff0c\u6d88\u8d39\u8005\u51e0\u4e4e\u53ef\u4ee5\u5b9e\u65f6\u7684\u88ab\u901a\u77e5\u3002\n\u5c3d\u7ba1\u4f1a\u6709\u4e00\u70b9\u70b9\u5e95\u5c42\u7684I/O\u635f\u8017\uff0c\u4f7f\u7528\u5b83\u901a\u5e38\u4f1a\u83b7\u5f97\u66f4\u597d\u7684\u54cd\u5e94\u65f6\u95f4\u5e76\u7b80\u5316\u7f16\u7a0b\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 12.14 \u5728Unix\u7cfb\u7edf\u4e0a\u9762\u542f\u52a8\u5b88\u62a4\u8fdb\u7a0b\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u95ee\u9898\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4f60\u60f3\u7f16\u5199\u4e00\u4e2a\u4f5c\u4e3a\u4e00\u4e2a\u5728Unix\u6216\u7c7bUnix\u7cfb\u7edf\u4e0a\u9762\u8fd0\u884c\u7684\u5b88\u62a4\u8fdb\u7a0b\u8fd0\u884c\u7684\u7a0b\u5e8f\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u89e3\u51b3\u65b9\u6848\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u521b\u5efa\u4e00\u4e2a\u6b63\u786e\u7684\u5b88\u62a4\u8fdb\u7a0b\u9700\u8981\u4e00\u4e2a\u7cbe\u786e\u7684\u7cfb\u7edf\u8c03\u7528\u5e8f\u5217\u4ee5\u53ca\u5bf9\u4e8e\u7ec6\u8282\u7684\u63a7\u5236\u3002\n\u4e0b\u9762\u7684\u4ee3\u7801\u5c55\u793a\u4e86\u600e\u6837\u5b9a\u4e49\u4e00\u4e2a\u5b88\u62a4\u8fdb\u7a0b\uff0c\u53ef\u4ee5\u542f\u52a8\u540e\u5f88\u5bb9\u6613\u7684\u505c\u6b62\u5b83\u3002"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "#!/usr/bin/env python3\n# daemon.py\n\nimport os\nimport sys\n\nimport atexit\nimport signal\n\ndef daemonize(pidfile, *, stdin='/dev/null',\n                          stdout='/dev/null',\n                          stderr='/dev/null'):\n\n    if os.path.exists(pidfile):\n        raise RuntimeError('Already running')\n\n    # First fork (detaches from parent)\n    try:\n        if os.fork() > 0:\n            raise SystemExit(0)   # Parent exit\n    except OSError as e:\n        raise RuntimeError('fork #1 failed.')\n\n    os.chdir('/')\n    os.umask(0)\n    os.setsid()\n    # Second fork (relinquish session leadership)\n    try:\n        if os.fork() > 0:\n            raise SystemExit(0)\n    except OSError as e:\n        raise RuntimeError('fork #2 failed.')\n\n    # Flush I/O buffers\n    sys.stdout.flush()\n    sys.stderr.flush()\n\n    # Replace file descriptors for stdin, stdout, and stderr\n    with open(stdin, 'rb', 0) as f:\n        os.dup2(f.fileno(), sys.stdin.fileno())\n    with open(stdout, 'ab', 0) as f:\n        os.dup2(f.fileno(), sys.stdout.fileno())\n    with open(stderr, 'ab', 0) as f:\n        os.dup2(f.fileno(), sys.stderr.fileno())\n\n    # Write the PID file\n    with open(pidfile,'w') as f:\n        print(os.getpid(),file=f)\n\n    # Arrange to have the PID file removed on exit/signal\n    atexit.register(lambda: os.remove(pidfile))\n\n    # Signal handler for termination (required)\n    def sigterm_handler(signo, frame):\n        raise SystemExit(1)\n\n    signal.signal(signal.SIGTERM, sigterm_handler)\n\ndef main():\n    import time\n    sys.stdout.write('Daemon started with pid {}\\n'.format(os.getpid()))\n    while True:\n        sys.stdout.write('Daemon Alive! {}\\n'.format(time.ctime()))\n        time.sleep(10)\n\nif __name__ == '__main__':\n    PIDFILE = '/tmp/daemon.pid'\n\n    if len(sys.argv) != 2:\n        print('Usage: {} [start|stop]'.format(sys.argv[0]), file=sys.stderr)\n        raise SystemExit(1)\n\n    if sys.argv[1] == 'start':\n        try:\n            daemonize(PIDFILE,\n                      stdout='/tmp/daemon.log',\n                      stderr='/tmp/dameon.log')\n        except RuntimeError as e:\n            print(e, file=sys.stderr)\n            raise SystemExit(1)\n\n        main()\n\n    elif sys.argv[1] == 'stop':\n        if os.path.exists(PIDFILE):\n            with open(PIDFILE) as f:\n                os.kill(int(f.read()), signal.SIGTERM)\n        else:\n            print('Not running', file=sys.stderr)\n            raise SystemExit(1)\n\n    else:\n        print('Unknown command {!r}'.format(sys.argv[1]), file=sys.stderr)\n        raise SystemExit(1)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u8981\u542f\u52a8\u8fd9\u4e2a\u5b88\u62a4\u8fdb\u7a0b\uff0c\u7528\u6237\u9700\u8981\u4f7f\u7528\u5982\u4e0b\u7684\u547d\u4ee4\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "bash % daemon.py start\nbash % cat /tmp/daemon.pid\n2882\nbash % tail -f /tmp/daemon.log\nDaemon started with pid 2882\nDaemon Alive! Fri Oct 12 13:45:37 2012\nDaemon Alive! Fri Oct 12 13:45:47 2012\n..."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5b88\u62a4\u8fdb\u7a0b\u53ef\u4ee5\u5b8c\u5168\u5728\u540e\u53f0\u8fd0\u884c\uff0c\u56e0\u6b64\u8fd9\u4e2a\u547d\u4ee4\u4f1a\u7acb\u5373\u8fd4\u56de\u3002\n\u4e0d\u8fc7\uff0c\u4f60\u53ef\u4ee5\u50cf\u4e0a\u9762\u90a3\u6837\u67e5\u770b\u4e0e\u5b83\u76f8\u5173\u7684pid\u6587\u4ef6\u548c\u65e5\u5fd7\u3002\u8981\u505c\u6b62\u8fd9\u4e2a\u5b88\u62a4\u8fdb\u7a0b\uff0c\u4f7f\u7528\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "bash % daemon.py stop\nbash %"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u8ba8\u8bba\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u672c\u8282\u5b9a\u4e49\u4e86\u4e00\u4e2a\u51fd\u6570 daemonize() \uff0c\u5728\u7a0b\u5e8f\u542f\u52a8\u65f6\u88ab\u8c03\u7528\u4f7f\u5f97\u7a0b\u5e8f\u4ee5\u4e00\u4e2a\u5b88\u62a4\u8fdb\u7a0b\u6765\u8fd0\u884c\u3002\ndaemonize() \u51fd\u6570\u53ea\u63a5\u53d7\u5173\u952e\u5b57\u53c2\u6570\uff0c\u8fd9\u6837\u7684\u8bdd\u53ef\u9009\u53c2\u6570\u5728\u88ab\u4f7f\u7528\u65f6\u5c31\u66f4\u6e05\u6670\u4e86\u3002\n\u5b83\u4f1a\u5f3a\u5236\u7528\u6237\u50cf\u4e0b\u9762\u8fd9\u6837\u4f7f\u7528\u5b83\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "daemonize('daemon.pid',\n          stdin='/dev/null,\n          stdout='/tmp/daemon.log',\n          stderr='/tmp/daemon.log')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u800c\u4e0d\u662f\u50cf\u4e0b\u9762\u8fd9\u6837\u542b\u7cca\u4e0d\u6e05\u7684\u8c03\u7528\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# Illegal. Must use keyword arguments\ndaemonize('daemon.pid',\n          '/dev/null', '/tmp/daemon.log','/tmp/daemon.log')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u521b\u5efa\u4e00\u4e2a\u5b88\u62a4\u8fdb\u7a0b\u7684\u6b65\u9aa4\u770b\u4e0a\u53bb\u4e0d\u662f\u5f88\u6613\u61c2\uff0c\u4f46\u662f\u5927\u4f53\u601d\u60f3\u662f\u8fd9\u6837\u7684\uff0c\n\u9996\u5148\uff0c\u4e00\u4e2a\u5b88\u62a4\u8fdb\u7a0b\u5fc5\u987b\u8981\u4ece\u7236\u8fdb\u7a0b\u4e2d\u8131\u79bb\u3002\n\u8fd9\u662f\u7531 os.fork() \u64cd\u4f5c\u6765\u5b8c\u6210\u7684\uff0c\u5e76\u7acb\u5373\u88ab\u7236\u8fdb\u7a0b\u7ec8\u6b62\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5728\u5b50\u8fdb\u7a0b\u53d8\u6210\u5b64\u513f\u540e\uff0c\u8c03\u7528 os.setsid() \u521b\u5efa\u4e86\u4e00\u4e2a\u5168\u65b0\u7684\u8fdb\u7a0b\u4f1a\u8bdd\uff0c\u5e76\u8bbe\u7f6e\u5b50\u8fdb\u7a0b\u4e3a\u9996\u9886\u3002\n\u5b83\u4f1a\u8bbe\u7f6e\u8fd9\u4e2a\u5b50\u8fdb\u7a0b\u4e3a\u65b0\u7684\u8fdb\u7a0b\u7ec4\u7684\u9996\u9886\uff0c\u5e76\u786e\u4fdd\u4e0d\u4f1a\u518d\u6709\u63a7\u5236\u7ec8\u7aef\u3002\n\u5982\u679c\u8fd9\u4e9b\u542c\u4e0a\u53bb\u592a\u9b54\u5e7b\uff0c\u56e0\u4e3a\u5b83\u9700\u8981\u5c06\u5b88\u62a4\u8fdb\u7a0b\u540c\u7ec8\u7aef\u5206\u79bb\u5f00\u5e76\u786e\u4fdd\u4fe1\u53f7\u673a\u5236\u5bf9\u5b83\u4e0d\u8d77\u4f5c\u7528\u3002\n\u8c03\u7528 os.chdir() \u548c os.umask(0) \u6539\u53d8\u4e86\u5f53\u524d\u5de5\u4f5c\u76ee\u5f55\u5e76\u91cd\u7f6e\u6587\u4ef6\u6743\u9650\u63a9\u7801\u3002\n\u4fee\u6539\u76ee\u5f55\u901a\u5e38\u662f\u4e2a\u597d\u4e3b\u610f\uff0c\u56e0\u4e3a\u8fd9\u6837\u53ef\u4ee5\u4f7f\u5f97\u5b83\u4e0d\u518d\u5de5\u4f5c\u5728\u88ab\u542f\u52a8\u65f6\u7684\u76ee\u5f55\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u53e6\u5916\u4e00\u4e2a\u8c03\u7528 os.fork() \u5728\u8fd9\u91cc\u66f4\u52a0\u795e\u79d8\u70b9\u3002\n\u8fd9\u4e00\u6b65\u4f7f\u5f97\u5b88\u62a4\u8fdb\u7a0b\u5931\u53bb\u4e86\u83b7\u53d6\u65b0\u7684\u63a7\u5236\u7ec8\u7aef\u7684\u80fd\u529b\u5e76\u4e14\u8ba9\u5b83\u66f4\u52a0\u72ec\u7acb\n\uff08\u672c\u8d28\u4e0a\uff0c\u8be5daemon\u653e\u5f03\u4e86\u5b83\u7684\u4f1a\u8bdd\u9996\u9886\u4f4e\u4f4d\uff0c\u56e0\u6b64\u518d\u4e5f\u6ca1\u6709\u6743\u9650\u53bb\u6253\u5f00\u63a7\u5236\u7ec8\u7aef\u4e86\uff09\u3002\n\u5c3d\u7ba1\u4f60\u53ef\u4ee5\u5ffd\u7565\u8fd9\u4e00\u6b65\uff0c\u4f46\u662f\u6700\u597d\u4e0d\u8981\u8fd9\u4e48\u505a\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4e00\u65e6\u5b88\u62a4\u8fdb\u7a0b\u88ab\u6b63\u786e\u7684\u5206\u79bb\uff0c\u5b83\u4f1a\u91cd\u65b0\u521d\u59cb\u5316\u6807\u51c6I/O\u6d41\u6307\u5411\u7528\u6237\u6307\u5b9a\u7684\u6587\u4ef6\u3002\n\u8fd9\u4e00\u90e8\u5206\u6709\u70b9\u96be\u61c2\u3002\u8ddf\u6807\u51c6I/O\u6d41\u76f8\u5173\u7684\u6587\u4ef6\u5bf9\u8c61\u7684\u5f15\u7528\u5728\u89e3\u91ca\u5668\u4e2d\u591a\u4e2a\u5730\u65b9\u88ab\u627e\u5230\n\uff08sys.stdout, sys.__stdout__\u7b49\uff09\u3002\n\u4ec5\u4ec5\u7b80\u5355\u7684\u5173\u95ed sys.stdout \u5e76\u91cd\u65b0\u6307\u5b9a\u5b83\u662f\u884c\u4e0d\u901a\u7684\uff0c\n\u56e0\u4e3a\u6ca1\u529e\u6cd5\u77e5\u9053\u5b83\u662f\u5426\u5168\u90e8\u90fd\u662f\u7528\u7684\u662f sys.stdout \u3002\n\u8fd9\u91cc\uff0c\u6211\u4eec\u6253\u5f00\u4e86\u4e00\u4e2a\u5355\u72ec\u7684\u6587\u4ef6\u5bf9\u8c61\uff0c\u5e76\u8c03\u7528 os.dup2() \uff0c\n\u7528\u5b83\u6765\u4ee3\u66ff\u88ab sys.stdout \u4f7f\u7528\u7684\u6587\u4ef6\u63cf\u8ff0\u7b26\u3002\n\u8fd9\u6837\uff0csys.stdout \u4f7f\u7528\u7684\u539f\u59cb\u6587\u4ef6\u4f1a\u88ab\u5173\u95ed\u5e76\u7531\u65b0\u7684\u6765\u66ff\u6362\u3002\n\u8fd8\u8981\u5f3a\u8c03\u7684\u662f\u4efb\u4f55\u7528\u4e8e\u6587\u4ef6\u7f16\u7801\u6216\u6587\u672c\u5904\u7406\u7684\u6807\u51c6I/O\u6d41\u8fd8\u4f1a\u4fdd\u7559\u539f\u72b6\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5b88\u62a4\u8fdb\u7a0b\u7684\u4e00\u4e2a\u901a\u5e38\u5b9e\u8df5\u662f\u5728\u4e00\u4e2a\u6587\u4ef6\u4e2d\u5199\u5165\u8fdb\u7a0bID\uff0c\u53ef\u4ee5\u88ab\u5176\u4ed6\u7a0b\u5e8f\u540e\u9762\u4f7f\u7528\u5230\u3002\ndaemonize() \u51fd\u6570\u7684\u6700\u540e\u90e8\u5206\u5199\u4e86\u8fd9\u4e2a\u6587\u4ef6\uff0c\u4f46\u662f\u5728\u7a0b\u5e8f\u7ec8\u6b62\u65f6\u5220\u9664\u4e86\u5b83\u3002\natexit.register() \u51fd\u6570\u6ce8\u518c\u4e86\u4e00\u4e2a\u51fd\u6570\u5728Python\u89e3\u91ca\u5668\u7ec8\u6b62\u65f6\u6267\u884c\u3002\n\u4e00\u4e2a\u5bf9\u4e8eSIGTERM\u7684\u4fe1\u53f7\u5904\u7406\u5668\u7684\u5b9a\u4e49\u540c\u6837\u9700\u8981\u88ab\u4f18\u96c5\u7684\u5173\u95ed\u3002\n\u4fe1\u53f7\u5904\u7406\u5668\u7b80\u5355\u7684\u629b\u51fa\u4e86 SystemExit() \u5f02\u5e38\u3002\n\u6216\u8bb8\u8fd9\u4e00\u6b65\u770b\u4e0a\u53bb\u6ca1\u5fc5\u8981\uff0c\u4f46\u662f\u6ca1\u6709\u5b83\uff0c\n\u7ec8\u6b62\u4fe1\u53f7\u4f1a\u4f7f\u5f97\u4e0d\u6267\u884c atexit.register() \u6ce8\u518c\u7684\u6e05\u7406\u64cd\u4f5c\u7684\u65f6\u5019\u5c31\u6740\u6389\u4e86\u89e3\u91ca\u5668\u3002\n\u4e00\u4e2a\u6740\u6389\u8fdb\u7a0b\u7684\u4f8b\u5b50\u4ee3\u7801\u53ef\u4ee5\u5728\u7a0b\u5e8f\u6700\u540e\u7684 stop \u547d\u4ee4\u7684\u64cd\u4f5c\u4e2d\u770b\u5230\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u66f4\u591a\u5173\u4e8e\u7f16\u5199\u5b88\u62a4\u8fdb\u7a0b\u7684\u4fe1\u606f\u53ef\u4ee5\u67e5\u770b\u300aUNIX \u73af\u5883\u9ad8\u7ea7\u7f16\u7a0b\u300b, \u7b2c\u4e8c\u7248\nby W. Richard Stevens and Stephen A. Rago (Addison-Wesley, 2005)\u3002\n\u5c3d\u7ba1\u5b83\u662f\u5173\u6ce8\u4e0eC\u8bed\u8a00\u7f16\u7a0b\uff0c\u4f46\u662f\u6240\u6709\u7684\u5185\u5bb9\u90fd\u9002\u7528\u4e8ePython\uff0c\n\u56e0\u4e3a\u6240\u6709\u9700\u8981\u7684POSIX\u51fd\u6570\u90fd\u53ef\u4ee5\u5728\u6807\u51c6\u5e93\u4e2d\u627e\u5230\u3002"
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.7.1"
    },
    "toc": {
      "base_numbering": 1,
      "nav_menu": {},
      "number_sections": true,
      "sideBar": true,
      "skip_h1_title": true,
      "title_cell": "Table of Contents",
      "title_sidebar": "Contents",
      "toc_cell": false,
      "toc_position": {},
      "toc_section_display": true,
      "toc_window_display": true
    }
  },
  "nbformat": 4,
  "nbformat_minor": 2
}